diff --git a/bsp/spacemit/dm/Kconfig b/bsp/spacemit/dm/Kconfig new file mode 100644 index 000000000000..0fdd2b6ae726 --- /dev/null +++ b/bsp/spacemit/dm/Kconfig @@ -0,0 +1,31 @@ +SOC_DM_ADC_DIR = $(SOC_DM_DIR)/adc +SOC_DM_AUDIO_DIR = $(SOC_DM_DIR)/audio +SOC_DM_CLK_DIR = $(SOC_DM_DIR)/clk +SOC_DM_DMA_DIR = $(SOC_DM_DIR)/dma +SOC_DM_DVFS_CPUFREQ_DIR = $(SOC_DM_DIR)/dvfs/cpufreq +SOC_DM_ETHERNET_DIR = $(SOC_DM_DIR)/ethernet +SOC_DM_GRAPHIC_FB_DIR = $(SOC_DM_DIR)/graphic/framebuffer +SOC_DM_GRAPHIC_LOGO_DIR = $(SOC_DM_DIR)/graphic/logo +SOC_DM_HWCRYPTO_DIR = $(SOC_DM_DIR)/hwcrypto +SOC_DM_CLOCK_TIME_DIR = $(SOC_DM_DIR)/clock_time +SOC_DM_I2C_DIR = $(SOC_DM_DIR)/i2c +SOC_DM_INPUT_MISC_DIR = $(SOC_DM_DIR)/input/misc +SOC_DM_MBOX_DIR = $(SOC_DM_DIR)/mailbox +SOC_DM_MFD_DIR = $(SOC_DM_DIR)/mfd +SOC_DM_NVMEM_DIR = $(SOC_DM_DIR)/nvmem +SOC_DM_PCI_DIR = $(SOC_DM_DIR)/pci +SOC_DM_PIC_DIR = $(RTT_DIR)/libcpu/risc-v/common/pic +SOC_DM_PIN_DIR = $(SOC_DM_DIR)/pin +SOC_DM_PINCTRL_DIR = $(SOC_DM_DIR)/pinctrl +SOC_DM_PMDOMAIN_DIR = $(SOC_DM_DIR)/pmdomain +SOC_DM_POWER_RESET_DIR = $(SOC_DM_DIR)/power/reset +SOC_DM_PWM_DIR = $(SOC_DM_DIR)/pwm +SOC_DM_REGULATOR_DIR = $(SOC_DM_DIR)/regulator +SOC_DM_RESET_DIR = $(SOC_DM_DIR)/reset +SOC_DM_RTC_DIR = $(SOC_DM_DIR)/rtc +SOC_DM_SDIO_DIR = $(SOC_DM_DIR)/sdio +SOC_DM_SERIAL_DIR = $(SOC_DM_DIR)/serial +SOC_DM_SOC_DIR = $(SOC_DM_DIR)/soc +SOC_DM_SPI_DIR = $(SOC_DM_DIR)/spi +SOC_DM_THERMAL_DIR = $(SOC_DM_DIR)/thermal +SOC_DM_WDT_DIR = $(SOC_DM_DIR)/watchdog diff --git a/bsp/spacemit/dm/SConscript b/bsp/spacemit/dm/SConscript new file mode 100644 index 000000000000..3d15055d62d2 --- /dev/null +++ b/bsp/spacemit/dm/SConscript @@ -0,0 +1,13 @@ +import os +from building import * + +cwd = GetCurrentDir() +objs = [] +list = os.listdir(cwd) + +for d in list: + path = os.path.join(cwd, d) + if os.path.isfile(os.path.join(path, 'SConscript')): + objs = objs + SConscript(os.path.join(d, 'SConscript')) + +Return('objs') diff --git a/bsp/spacemit/dm/adc/Kconfig b/bsp/spacemit/dm/adc/Kconfig new file mode 100644 index 000000000000..b93a301f8e60 --- /dev/null +++ b/bsp/spacemit/dm/adc/Kconfig @@ -0,0 +1,6 @@ +config RT_ADC_SPACEMIT_PMIC + bool "Spacemit PMIC ADC driver" + depends on RT_USING_DM + depends on RT_USING_ADC + depends on RT_MFD_SPACEMIT_PMIC + default n diff --git a/bsp/spacemit/dm/adc/SConscript b/bsp/spacemit/dm/adc/SConscript new file mode 100644 index 000000000000..a8ffbf9482dc --- /dev/null +++ b/bsp/spacemit/dm/adc/SConscript @@ -0,0 +1,14 @@ +from building import * + +group = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +src = [] + +if GetDepend(['RT_ADC_SPACEMIT_PMIC']): + src += ['adc-spacemit-pmic.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/adc/adc-spacemit-pmic.c b/bsp/spacemit/dm/adc/adc-spacemit-pmic.c new file mode 100644 index 000000000000..b7bf65b00a7c --- /dev/null +++ b/bsp/spacemit/dm/adc/adc-spacemit-pmic.c @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#define DBG_TAG "adc.spacemit-pmic" +#define DBG_LVL DBG_INFO +#include + +#define __SPACEMIT_ADC_INTERNAL +#include + +#define SPACEMIT_PMIC_ADC_TIMEOUT_MS 1000 + +struct spacemit_pmic_adc +{ + struct rt_adc_device parent; + + int irq; + + struct spacemit_pmic *pmic; + const struct spacemit_pmic_adc_data *data; + + struct rt_mutex lock; + struct rt_completion completion; +}; + +#define raw_to_spacemit_pmic_adc(raw) rt_container_of(raw, struct spacemit_pmic_adc, parent) + +static rt_err_t spacemit_pmic_adc_enabled(struct rt_adc_device *device, + rt_int8_t channel, rt_bool_t enabled) +{ + struct spacemit_pmic_adc *pmic_adc = raw_to_spacemit_pmic_adc(device); + + if (channel < 0 || channel >= pmic_adc->data->iio_desc_nr) + { + return -RT_EINVAL; + } + + return RT_EOK; +} + +static rt_err_t spacemit_pmic_adc_convert(struct rt_adc_device *device, + rt_int8_t channel, rt_uint32_t *value) +{ + rt_err_t err; + rt_uint32_t tmp, adc_val_h, adc_val_l; + struct spacemit_pmic_adc *pmic_adc = raw_to_spacemit_pmic_adc(device); + struct spacemit_pmic *pmic = pmic_adc->pmic; + + if (!value || channel < 0 || channel >= pmic_adc->data->iio_desc_nr) + { + return -RT_EINVAL; + } + + if ((err = rt_mutex_take(&pmic_adc->lock, RT_WAITING_FOREVER))) + { + return err; + } + + /* Reset the ADC auto register */ + if ((err = spacemit_pmic_update_bits(pmic, SPM8821_ADC_AUTO_REG, + SPM8821_ADC_AUTO_BIT_MSK, 0))) + { + goto _out_lock; + } + + /* Enable the ADC : ADC_CTRL[0] */ + if ((err = spacemit_pmic_update_bits(pmic, SPM8821_ADC_CTRL_REG, + SPM8821_ADC_CTRL_BIT_MSK, (1 << SPM8821_ADC_CTRL_EN_BIT_OFFSET)))) + { + goto _out_lock; + } + + /* Choose the channel of adc : ADC_CFG[1] */ + if ((err = spacemit_pmic_update_bits(pmic, SPM8821_ADC_CFG1_REG, + SPM8821_ADC_CFG1_ADC_CHNNL_SEL_BIT_MSK, + (channel + SPM8821_ADC_EXTERNAL_CHANNEL_OFFSET) << + SPM8821_ADC_CFG1_ADC_CHNNL_SEL_BIT_OFFSET))) + { + goto _out_lock; + } + + rt_completion_init(&pmic_adc->completion); + + /* ADC go */ + if ((err = spacemit_pmic_update_bits(pmic, SPM8821_ADC_CTRL_REG, + SPM8821_ADC_CTRL_BIT_MSK, + (1 << SPM8821_ADC_CTRL_GO_BIT_OFFSET) | + (1 << SPM8821_ADC_CTRL_EN_BIT_OFFSET)))) + { + goto _out_lock; + } + + err = rt_completion_wait(&pmic_adc->completion, + rt_tick_from_millisecond(SPACEMIT_PMIC_ADC_TIMEOUT_MS)); + + if (err) + { + unsigned long auto_reg, cfg1, cfg2, ctrl; + unsigned long enable, result_h, result_l, status; + + ctrl = spacemit_pmic_read(pmic, SPM8821_ADC_CTRL_REG); + cfg1 = spacemit_pmic_read(pmic, SPM8821_ADC_CFG1_REG); + cfg2 = spacemit_pmic_read(pmic, SPM8821_ADC_CFG2_REG); + auto_reg = spacemit_pmic_read(pmic, SPM8821_ADC_AUTO_REG); + status = spacemit_pmic_read(pmic, SPM8821_E_STATUS_REG_BASE + 1); + enable = spacemit_pmic_read(pmic, SPM8821_E_EN_REG_BASE + 1); + result_h = spacemit_pmic_read(pmic, + SPM8821_ADCIN0_RES_H_REG + channel * 2); + result_l = spacemit_pmic_read(pmic, + SPM8821_ADCIN0_RES_L_REG + channel * 2); + + LOG_E("ADC channel %d conversion timed out: %s", channel, rt_strerror(err)); + LOG_E("ADC regs: ctrl=%02lx cfg1=%02lx cfg2=%02lx auto=%02lx " + "status=%02lx enable=%02lx result=%02lx:%02lx", + ctrl, cfg1, cfg2, auto_reg, status, enable, result_h, result_l); + goto _out_lock; + } + + adc_val_h = spacemit_pmic_read(pmic, SPM8821_ADCIN0_RES_H_REG + channel * 2); + + if ((rt_err_t)adc_val_h < 0) + { + err = (rt_err_t)adc_val_h; + goto _out_lock; + } + + adc_val_l = spacemit_pmic_read(pmic, SPM8821_ADCIN0_RES_L_REG + channel * 2); + + if ((rt_err_t)adc_val_l < 0) + { + err = (rt_err_t)adc_val_l; + goto _out_lock; + } + + tmp = spacemit_pmic_read(pmic, SPM8821_VERSION_ID_REG); + + if ((rt_err_t)tmp < 0) + { + err = (rt_err_t)tmp; + goto _out_lock; + } + + *value = (adc_val_h << (__rt_ffs(SPM8821_ADCIN0_REG_L_BIT_MSK) - 1)) | + ((adc_val_l & SPM8821_ADCIN0_REG_L_BIT_MSK) >> + (__rt_ffs(SPM8821_ADCIN0_REG_L_BIT_MSK) - 1)); + + if (tmp == 0) + { + /* + * if the version of P1 is A, the data read from + * the register is the inverse of the real data + * and the conversion accuracy of P1 is 12 bits + */ + *value = 4095 - *value; + } + + err = RT_EOK; + +_out_lock: + rt_mutex_release(&pmic_adc->lock); + + return err; +} + +static rt_uint8_t spacemit_pmic_adc_get_resolution(struct rt_adc_device *device) +{ + return 12; +} + +static rt_int16_t spacemit_pmic_adc_get_vref(struct rt_adc_device *device) +{ + return 3000; +} + +static const struct rt_adc_ops spacemit_pmic_adc_ops = +{ + .enabled = spacemit_pmic_adc_enabled, + .convert = spacemit_pmic_adc_convert, + .get_resolution = spacemit_pmic_adc_get_resolution, + .get_vref = spacemit_pmic_adc_get_vref, +}; + +static void spacemit_pmic_adc_isr(int irq, void *param) +{ + struct spacemit_pmic_adc *pmic_adc = param; + + rt_completion_done(&pmic_adc->completion); +} + +static rt_err_t spacemit_pmic_adc_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + const char *dev_name; + struct rt_device *dev = &pdev->parent; + struct spacemit_pmic *pmic = pdev->priv; + struct spacemit_pmic_adc *pmic_adc = rt_calloc(1, sizeof(*pmic_adc)); + const struct spacemit_pmic_adc_data *data = pdev->id->data; + + if (!pmic_adc) + { + return -RT_ENOMEM; + } + + pmic_adc->pmic = pmic; + pmic_adc->data = data; + + if ((pmic_adc->irq = rt_dm_dev_get_irq(dev, 0)) < 0) + { + err = pmic_adc->irq; + goto _fail; + } + + /* Enable chop */ + if ((err = spacemit_pmic_update_bits(pmic, + SPM8821_ADC_CFG1_REG, + SPM8821_ADC_CFG1_ADC_CHOP_EN_BIT_MSK, + 1 << SPM8821_ADC_CFG1_ADC_CHOP_EN_BIT_OFFSET))) + { + goto _fail; + } + + /* Set the vref: 3v3 */ + if ((err = spacemit_pmic_update_bits(pmic, + SPM8821_ADC_CFG2_REG, + SPM8821_ADC_CFG2_REF_SEL_BIT_MSK, + SPM8821_ADC_CFG2_3V3_REF << SPM8821_ADC_CFG2_REF_SEL_BIT_OFFSET))) + { + goto _fail; + } + + /* Set adc deb num: 7 */ + if ((err = spacemit_pmic_update_bits(pmic, + SPM8821_ADC_CFG2_REG, + SPM8821_ADC_CFG2_DEB_NUM_BIT_MSK, + SPM8821_ADC_CFG2_7_DEB_NUM << SPM8821_ADC_CFG2_DEB_NUM_BIT_OFFSET))) + { + goto _fail; + } + + dev->user_data = pmic_adc; + + rt_dm_dev_set_name_auto(&pmic_adc->parent.parent, "adc"); + dev_name = rt_dm_dev_get_name(&pmic_adc->parent.parent); + + if ((err = rt_mutex_init(&pmic_adc->lock, dev_name, RT_IPC_FLAG_PRIO))) + { + goto _fail; + } + + rt_completion_init(&pmic_adc->completion); + + if ((err = rt_hw_adc_register(&pmic_adc->parent, dev_name, + &spacemit_pmic_adc_ops, pmic_adc))) + { + rt_mutex_detach(&pmic_adc->lock); + goto _fail; + } + + rt_hw_interrupt_install(pmic_adc->irq, spacemit_pmic_adc_isr, pmic_adc, "adc-spacemit-pmic"); + rt_hw_interrupt_umask(pmic_adc->irq); + + rt_dm_dev_bind_fwdata(dev, RT_NULL, pmic_adc); + + return RT_EOK; + +_fail: + rt_free(pmic_adc); + + return err; +} + +static rt_err_t spacemit_pmic_adc_remove(struct rt_platform_device *pdev) +{ + struct spacemit_pmic_adc *pmic_adc = pdev->parent.user_data; + + rt_hw_interrupt_mask(pmic_adc->irq); + rt_pic_detach_irq(pmic_adc->irq, pmic_adc); + + rt_device_unregister(&pmic_adc->parent.parent); + rt_mutex_detach(&pmic_adc->lock); + + rt_free(pmic_adc); + + return RT_EOK; +} + +static const struct rt_ofw_node_id spacemit_pmic_adc_ofw_ids[] = +{ + { .compatible = "pmic,adc,spm8821", .data = &spm8821_adc_data }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_pmic_adc_driver = +{ + .name = "spacemit-pmic-adc", + .ids = spacemit_pmic_adc_ofw_ids, + + .probe = spacemit_pmic_adc_probe, + .remove = spacemit_pmic_adc_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(spacemit_pmic_adc_driver); diff --git a/bsp/spacemit/dm/audio/Kconfig b/bsp/spacemit/dm/audio/Kconfig new file mode 100644 index 000000000000..85d9b65f7485 --- /dev/null +++ b/bsp/spacemit/dm/audio/Kconfig @@ -0,0 +1,29 @@ +config RT_AUDIO_SPACEMIT + bool "Spacemit K1 audio" + depends on RT_USING_AUDIO + depends on RT_USING_OFW + depends on RT_USING_DMA + depends on RT_USING_CLK + depends on RT_USING_RESET + depends on RT_USING_PIN + depends on RT_USING_I2C + depends on RT_USING_RPMSG + depends on RT_VIRTIO_RPMSG + depends on RT_SOC_SPACEMIT_K1X_RPROC + select RT_AUDIO_SPACEMIT_CODEC_ES8326 + default n + help + Enable the K1 I2S and HDMI audio paths. Both cards operate at 48 kHz, + stereo, 16-bit PCM. The HDMI card supports playback. + +config RT_AUDIO_SPACEMIT_CODEC + bool "Spacemit codec support" + depends on RT_AUDIO_SPACEMIT + default y + +config RT_AUDIO_SPACEMIT_CODEC_ES8326 + bool "ES8326 codec" + depends on RT_AUDIO_SPACEMIT_CODEC + default y + help + ES8326 codec supports playback and capture diff --git a/bsp/spacemit/dm/audio/SConscript b/bsp/spacemit/dm/audio/SConscript new file mode 100644 index 000000000000..352f617cebde --- /dev/null +++ b/bsp/spacemit/dm/audio/SConscript @@ -0,0 +1,15 @@ +from building import * + +cwd = GetCurrentDir() +src = [] + +if GetDepend(['RT_AUDIO_SPACEMIT']): + src += ['spacemit-snd-card.c', 'spacemit-snd-i2s.c', 'spacemit-snd-pcm-dma.c', 'spacemit-snd-sspa.c'] + +if GetDepend(['RT_AUDIO_SPACEMIT_CODEC_ES8326']): + src += ['codec/es8326.c'] + +group = DefineGroup('DeviceDrivers', src, depend=[], + CPPPATH=[cwd, cwd + '/../include']) + +Return('group') diff --git a/bsp/spacemit/dm/audio/codec/es8326.c b/bsp/spacemit/dm/audio/codec/es8326.c new file mode 100644 index 000000000000..114fa580935b --- /dev/null +++ b/bsp/spacemit/dm/audio/codec/es8326.c @@ -0,0 +1,528 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#define DBG_TAG "codec.es8326" +#define DBG_LVL DBG_INFO +#include + +#include "spacemit-audio.h" +#include "es8326.h" + +struct es8326_codec +{ + struct rt_i2c_client *client; + struct rt_ofw_node *np; + struct rt_mutex lock; + + rt_uint8_t mic1_src; + rt_uint8_t mic2_src; + rt_uint8_t jack_pol; + rt_uint8_t interrupt_clk; + rt_uint8_t version; + rt_uint8_t volume; + + rt_base_t speaker_pin; + rt_uint8_t speaker_active; + rt_bool_t calibrated; + rt_bool_t muted; + + rt_list_t list; +}; + +struct es8326_coeff +{ + rt_uint16_t mclk_fs; + rt_uint8_t reg[8]; +}; + +static const struct es8326_coeff es8326_coeff_v0[] = +{ + { 64, { 0xe0, 0x00, 0x03, 0x2d, 0x4a, 0x0a, 0x1f, 0x1f } }, + { 128, { 0xe0, 0x01, 0x03, 0x2d, 0x4a, 0x0a, 0x1f, 0x1f } }, + { 256, { 0xe0, 0x00, 0x30, 0x2d, 0x4a, 0x0a, 0x1f, 0x1f } }, +}; + +static const struct es8326_coeff es8326_coeff_v3[] = +{ + { 64, { 0xe0, 0x00, 0x31, 0x2d, 0xca, 0x0a, 0x1f, 0x1f } }, + { 128, { 0xe0, 0x00, 0x01, 0x2d, 0xca, 0x0a, 0x1f, 0x1f } }, + { 256, { 0xe0, 0x00, 0x30, 0x2d, 0xca, 0x0a, 0x1f, 0x1f } }, +}; + +static rt_list_t codec_nodes = RT_LIST_OBJECT_INIT(codec_nodes); +static RT_DEFINE_SPINLOCK(codec_nodes_lock); + +static rt_err_t es8326_write_reg(struct es8326_codec *codec, + rt_uint8_t reg, rt_uint8_t value) +{ + rt_uint8_t data[2] = { reg, value }; + + return rt_i2c_master_send(codec->client->bus, codec->client->client_addr, + RT_I2C_WR, data, sizeof(data)) == sizeof(data) ? RT_EOK : -RT_EIO; +} + +static rt_err_t es8326_read_reg(struct es8326_codec *codec, + rt_uint8_t reg, rt_uint8_t *value) +{ + struct rt_i2c_msg messages[2]; + + messages[0].addr = codec->client->client_addr; + messages[0].flags = RT_I2C_WR; + messages[0].buf = ® + messages[0].len = 1; + messages[1].addr = codec->client->client_addr; + messages[1].flags = RT_I2C_RD; + messages[1].buf = value; + messages[1].len = 1; + + return rt_i2c_transfer(codec->client->bus, messages, 2) == 2 ? + RT_EOK : -RT_EIO; +} + +static rt_err_t es8326_update_bits(struct es8326_codec *codec, + rt_uint8_t reg, rt_uint8_t mask, rt_uint8_t value) +{ + rt_err_t err; + rt_uint8_t old; + + if ((err = es8326_read_reg(codec, reg, &old))) + { + return err; + } + + value = (old & ~mask) | (value & mask); + return value == old ? RT_EOK : es8326_write_reg(codec, reg, value); +} + +static void es8326_speaker_set(struct es8326_codec *codec, rt_bool_t enable) +{ + if (codec->speaker_pin >= 0) + { + rt_pin_write(codec->speaker_pin, + enable ? codec->speaker_active : !codec->speaker_active); + } +} + +static rt_err_t es8326_calibrate(struct es8326_codec *codec) +{ + rt_err_t err; + rt_uint8_t status, offset_l, offset_r; + + if (codec->version != ES8326_VERSION_B || codec->calibrated) + { + return RT_EOK; + } + + LOG_D("ES8326 B revision headphone calibration begin"); + + if ((err = es8326_write_reg(codec, ES8326_CLK_INV, 0xc0)) || + (err = es8326_write_reg(codec, ES8326_CLK_DIV1, 0x03)) || + (err = es8326_write_reg(codec, ES8326_CLK_DLL, 0x30)) || + (err = es8326_write_reg(codec, ES8326_CLK_MUX, 0xed)) || + (err = es8326_write_reg(codec, ES8326_CLK_DAC_SEL, 0x08)) || + (err = es8326_write_reg(codec, ES8326_CLK_TRI, 0xc1)) || + (err = es8326_write_reg(codec, ES8326_DAC_MUTE, 0x03)) || + (err = es8326_write_reg(codec, ES8326_ANA_VSEL, 0x7f)) || + (err = es8326_write_reg(codec, ES8326_VMIDLOW, 0x23)) || + (err = es8326_write_reg(codec, ES8326_DAC2HPMIX, 0x88))) + { + return err; + } + + rt_thread_mdelay(16); + es8326_write_reg(codec, ES8326_HP_OFFSET_CAL, 0x8c); + rt_thread_mdelay(16); + es8326_write_reg(codec, ES8326_RESET, 0xc0); + rt_thread_mdelay(16); + es8326_write_reg(codec, ES8326_HP_OFFSET_CAL, ES8326_HP_OFF); + + if (!es8326_read_reg(codec, ES8326_CSM_MUTE_STA, &status) && + (status & 0xf0) != 0x40) + { + rt_thread_mdelay(50); + } + + es8326_write_reg(codec, ES8326_HP_CAL, 0xd4); + rt_thread_mdelay(200); + es8326_write_reg(codec, ES8326_HP_CAL, 0x4d); + rt_thread_mdelay(200); + es8326_write_reg(codec, ES8326_HP_CAL, ES8326_HP_OFF); + + if ((err = es8326_read_reg(codec, ES8326_HPL_OFFSET_INI, &offset_l)) || + (err = es8326_read_reg(codec, ES8326_HPR_OFFSET_INI, &offset_r))) + { + return err; + } + + es8326_write_reg(codec, ES8326_HP_OFFSET_CAL, 0x8c); + es8326_write_reg(codec, ES8326_HPL_OFFSET_INI, offset_l); + es8326_write_reg(codec, ES8326_HPR_OFFSET_INI, offset_r); + es8326_write_reg(codec, ES8326_CLK_INV, 0x00); + codec->calibrated = RT_TRUE; + + return RT_EOK; +} + +static rt_err_t es8326_hw_init(struct es8326_codec *codec) +{ + rt_err_t err; + rt_uint8_t id1, id2; + + if ((err = es8326_read_reg(codec, ES8326_CHIP_ID1, &id1)) || + (err = es8326_read_reg(codec, ES8326_CHIP_ID2, &id2)) || + (err = es8326_read_reg(codec, ES8326_CHIP_VERSION, &codec->version))) + { + return err; + } + + es8326_write_reg(codec, ES8326_RESET, 0x1f); + es8326_write_reg(codec, ES8326_VMIDSEL, 0x0e); + es8326_write_reg(codec, ES8326_ANA_LP, 0xf0); + rt_thread_mdelay(10); + es8326_write_reg(codec, ES8326_HPJACK_TIMER, 0xd9); + es8326_write_reg(codec, ES8326_ANA_MICBIAS, 0xd8); + es8326_write_reg(codec, ES8326_HPDET_TYPE, 0x83); + es8326_write_reg(codec, ES8326_CLK_RESAMPLE, 0x05); + es8326_write_reg(codec, ES8326_CLK_DIV_CPC, 0x89); + es8326_write_reg(codec, ES8326_CLK_CTL, ES8326_CLK_ON); + es8326_write_reg(codec, ES8326_RESET, 0x17); + es8326_write_reg(codec, ES8326_HP_MISC, 0x3d); + es8326_write_reg(codec, ES8326_PULLUP_CTL, 0x00); + + es8326_write_reg(codec, ES8326_HP_VOL, 0xc4); + es8326_write_reg(codec, ES8326_HP_DRIVER, 0xa7); + rt_hw_us_delay(2000); + es8326_write_reg(codec, ES8326_HP_DRIVER_REF, 0x23); + es8326_write_reg(codec, ES8326_HP_DRIVER_REF, 0x33); + es8326_write_reg(codec, ES8326_HP_DRIVER, 0xa1); + + es8326_write_reg(codec, ES8326_CLK_INV, 0x00); + es8326_write_reg(codec, ES8326_CLK_VMIDS1, 0xc4); + es8326_write_reg(codec, ES8326_CLK_VMIDS2, 0x81); + es8326_write_reg(codec, ES8326_CLK_CAL_TIME, 0x00); + + if ((err = es8326_calibrate(codec))) + { + return err; + } + + es8326_write_reg(codec, ES8326_DAC_CROSSTALK, 0xaa); + es8326_write_reg(codec, ES8326_DAC_RAMPRATE, 0x00); + es8326_write_reg(codec, ES8326_HP_CAL, ES8326_HP_OFF); + es8326_write_reg(codec, ES8326_ANA_LP, 0xf0); + es8326_write_reg(codec, ES8326_ANA_VSEL, 0x7f); + es8326_write_reg(codec, ES8326_VMIDLOW, 0x03); + es8326_write_reg(codec, ES8326_DAC_DSM, 0x08); + es8326_write_reg(codec, ES8326_DAC_VPPSCALE, 0x15); + es8326_write_reg(codec, ES8326_HPDET_TYPE, 0x80 | + ES8326_HP_DET_SRC_PIN9 | codec->jack_pol | + (codec->version == ES8326_VERSION_B ? 0 : 0x04)); + rt_thread_mdelay(60); + es8326_update_bits(codec, ES8326_HPDET_TYPE, 0x03, 0x00); + es8326_write_reg(codec, ES8326_INT_SOURCE, ES8326_INT_SRC_PIN9); + es8326_write_reg(codec, ES8326_INTOUT_IO, codec->interrupt_clk); + es8326_write_reg(codec, ES8326_SDINOUT1_IO, + ES8326_IO_DMIC_CLK << ES8326_SDINOUT1_SHIFT); + es8326_write_reg(codec, ES8326_SDINOUT23_IO, ES8326_IO_INPUT); + es8326_write_reg(codec, ES8326_ANA_PDN, 0x00); + es8326_write_reg(codec, ES8326_RESET, ES8326_CSM_ON); + es8326_update_bits(codec, ES8326_PGAGAIN, + ES8326_MIC_SEL_MASK, ES8326_MIC1_SEL); + es8326_update_bits(codec, ES8326_DAC_MUTE, + ES8326_MUTE_MASK, ES8326_MUTE); + es8326_write_reg(codec, ES8326_ADC_MUTE, 0x0f); + es8326_write_reg(codec, ES8326_ADC1_SRC, codec->mic1_src); + es8326_write_reg(codec, ES8326_ADC2_SRC, codec->mic2_src); + es8326_write_reg(codec, ES8326_FMT, ES8326_S16_LE); + + codec->muted = RT_TRUE; + LOG_D("ES8326 id=%02x%02x revision=%u", id1, id2, codec->version); + + return RT_EOK; +} + +struct es8326_codec *es8326_codec_find(struct rt_ofw_node *np) +{ + struct es8326_codec *codec; + + rt_spin_lock(&codec_nodes_lock); + rt_list_for_each_entry(codec, &codec_nodes, list) + { + if (codec->np == np) + { + rt_spin_unlock(&codec_nodes_lock); + return codec; + } + } + rt_spin_unlock(&codec_nodes_lock); + + return RT_NULL; +} + +rt_err_t es8326_codec_hw_params(struct es8326_codec *codec, + const struct spacemit_audio_config *config) +{ + const struct es8326_coeff *coeffs; + rt_size_t count; + rt_err_t err = -RT_EINVAL; + + if (!codec || !config || config->samplerate != 48000 || + config->channels != 2 || config->samplebits != 16) + { + return -RT_EINVAL; + } + + if (codec->version == 0) + { + coeffs = es8326_coeff_v0; + count = RT_ARRAY_SIZE(es8326_coeff_v0); + } + else + { + coeffs = es8326_coeff_v3; + count = RT_ARRAY_SIZE(es8326_coeff_v3); + } + + rt_mutex_take(&codec->lock, RT_WAITING_FOREVER); + for (rt_size_t i = 0; i < count; ++i) + { + if (coeffs[i].mclk_fs == config->mclk_fs) + { + err = es8326_update_bits(codec, ES8326_FMT, + ES8326_DATA_LEN_MASK, ES8326_S16_LE); + for (rt_size_t reg = 0; !err && reg < sizeof(coeffs[i].reg); ++reg) + { + err = es8326_write_reg(codec, ES8326_CLK_DIV1 + reg, + coeffs[i].reg[reg]); + } + break; + } + } + rt_mutex_release(&codec->lock); + + return err; +} + +rt_err_t es8326_codec_start(struct es8326_codec *codec, int stream) +{ + rt_err_t err = RT_EOK; + rt_uint8_t hpdet; + + if (!codec || (stream != AUDIO_STREAM_REPLAY && stream != AUDIO_STREAM_RECORD)) + { + return -RT_EINVAL; + } + + rt_mutex_take(&codec->lock, RT_WAITING_FOREVER); + if (stream == AUDIO_STREAM_REPLAY) + { + es8326_update_bits(codec, ES8326_DAC_DSM, 0x01, 0x01); + rt_hw_us_delay(1000); + es8326_update_bits(codec, ES8326_DAC_DSM, 0x01, 0x00); + rt_hw_us_delay(1000); + es8326_update_bits(codec, ES8326_HP_DRIVER_REF, 0x30, 0x20); + es8326_update_bits(codec, ES8326_HP_DRIVER_REF, 0x30, 0x30); + es8326_write_reg(codec, ES8326_HP_DRIVER, 0xa1); + es8326_write_reg(codec, ES8326_HP_CAL, ES8326_HP_ON); + err = es8326_update_bits(codec, ES8326_DAC_MUTE, + ES8326_MUTE_MASK, 0); + codec->muted = RT_FALSE; + + if (es8326_read_reg(codec, ES8326_HPDET_STA, &hpdet) || + !(hpdet & ES8326_HPINSERT_FLAG)) + { + es8326_speaker_set(codec, RT_TRUE); + } + } + else + { + rt_thread_mdelay(300); + err = es8326_update_bits(codec, ES8326_ADC_MUTE, 0x0f, 0x00); + } + rt_mutex_release(&codec->lock); + + return err; +} + +rt_err_t es8326_codec_stop(struct es8326_codec *codec, int stream) +{ + rt_err_t err; + + if (!codec || (stream != AUDIO_STREAM_REPLAY && stream != AUDIO_STREAM_RECORD)) + { + return -RT_EINVAL; + } + + rt_mutex_take(&codec->lock, RT_WAITING_FOREVER); + if (stream == AUDIO_STREAM_REPLAY) + { + es8326_speaker_set(codec, RT_FALSE); + es8326_write_reg(codec, ES8326_HP_CAL, ES8326_HP_OFF); + err = es8326_update_bits(codec, ES8326_DAC_MUTE, + ES8326_MUTE_MASK, ES8326_MUTE); + es8326_update_bits(codec, ES8326_HP_DRIVER_REF, 0x30, 0x00); + codec->muted = RT_TRUE; + } + else + { + err = es8326_update_bits(codec, ES8326_ADC_MUTE, 0x0f, 0x0f); + } + rt_mutex_release(&codec->lock); + + return err; +} + +rt_err_t es8326_codec_set_volume(struct es8326_codec *codec, int volume) +{ + rt_err_t err; + + if (!codec) + { + return -RT_EINVAL; + } + + if (volume < AUDIO_VOLUME_MIN) + { + volume = AUDIO_VOLUME_MIN; + } + if (volume > AUDIO_VOLUME_MAX) + { + volume = AUDIO_VOLUME_MAX; + } + rt_mutex_take(&codec->lock, RT_WAITING_FOREVER); + err = es8326_write_reg(codec, ES8326_DAC_VOL, + (rt_uint8_t)(volume * 0xbf / AUDIO_VOLUME_MAX)); + if (!err) + { + codec->volume = volume; + } + rt_mutex_release(&codec->lock); + + return err; +} + +rt_err_t es8326_codec_set_mute(struct es8326_codec *codec, rt_bool_t mute) +{ + rt_err_t err; + rt_uint8_t hpdet; + + if (!codec) + { + return -RT_EINVAL; + } + + rt_mutex_take(&codec->lock, RT_WAITING_FOREVER); + err = es8326_update_bits(codec, ES8326_DAC_MUTE, + ES8326_MUTE_MASK, mute ? ES8326_MUTE : 0); + if (!err) + { + codec->muted = mute; + if (mute) + { + es8326_speaker_set(codec, RT_FALSE); + } + else if (es8326_read_reg(codec, ES8326_HPDET_STA, &hpdet) || + !(hpdet & ES8326_HPINSERT_FLAG)) + { + es8326_speaker_set(codec, RT_TRUE); + } + } + rt_mutex_release(&codec->lock); + + return err; +} + +static rt_err_t es8326_probe(struct rt_i2c_client *client) +{ + rt_err_t err; + rt_uint8_t pin_mode; + struct es8326_codec *codec = rt_calloc(1, sizeof(*codec)); + + if (!codec) + { + return -RT_ENOMEM; + } + + codec->client = client; + codec->np = client->parent.ofw_node; + codec->mic1_src = ES8326_ADC_AMIC; + codec->mic2_src = ES8326_ADC_DMIC; + codec->jack_pol = ES8326_HP_TYPE_AUTO; + codec->volume = 70; + codec->speaker_pin = -1; + rt_mutex_init(&codec->lock, "es8326", RT_IPC_FLAG_PRIO); + + rt_ofw_prop_read_u8(codec->np, "everest,mic1-src", &codec->mic1_src); + rt_ofw_prop_read_u8(codec->np, "everest,mic2-src", &codec->mic2_src); + rt_ofw_prop_read_u8(codec->np, "everest,jack-pol", &codec->jack_pol); + rt_ofw_prop_read_u8(codec->np, "everest,interrupt-clk", &codec->interrupt_clk); + + codec->speaker_pin = rt_pin_get_named_pin(&client->parent, "spk-ctl", 0, + &pin_mode, &codec->speaker_active); + if (codec->speaker_pin >= 0) + { + rt_pin_mode(codec->speaker_pin, PIN_MODE_OUTPUT); + es8326_speaker_set(codec, RT_FALSE); + } + + if ((err = es8326_hw_init(codec)) || + (err = es8326_codec_hw_params(codec, + &(struct spacemit_audio_config){ 48000, 2, 16, 64 })) || + (err = es8326_codec_set_volume(codec, codec->volume))) + { + LOG_E("ES8326 initialization failed: %s", rt_strerror(err)); + rt_mutex_detach(&codec->lock); + rt_free(codec); + return err; + } + + rt_spin_lock(&codec_nodes_lock); + rt_list_insert_before(&codec_nodes, &codec->list); + rt_spin_unlock(&codec_nodes_lock); + + client->parent.user_data = codec; + rt_dm_dev_bind_fwdata(&client->parent, RT_NULL, codec); + + return RT_EOK; +} + +static rt_err_t es8326_remove(struct rt_i2c_client *client) +{ + struct es8326_codec *codec = client->parent.user_data; + + if (!codec) + { + return RT_EOK; + } + + es8326_speaker_set(codec, RT_FALSE); + rt_spin_lock(&codec_nodes_lock); + rt_list_remove(&codec->list); + rt_spin_unlock(&codec_nodes_lock); + rt_dm_dev_unbind_fwdata(&client->parent, RT_NULL); + rt_mutex_detach(&codec->lock); + rt_free(codec); + + return RT_EOK; +} + +static const struct rt_ofw_node_id es8326_ofw_ids[] = +{ + { .compatible = "everest,es8326" }, + { /* sentinel */ } +}; + +static struct rt_i2c_driver es8326_driver = +{ + .ofw_ids = es8326_ofw_ids, + .probe = es8326_probe, + .remove = es8326_remove, +}; +RT_I2C_DRIVER_EXPORT(es8326_driver); diff --git a/bsp/spacemit/dm/audio/codec/es8326.h b/bsp/spacemit/dm/audio/codec/es8326.h new file mode 100644 index 000000000000..57c58221d1ab --- /dev/null +++ b/bsp/spacemit/dm/audio/codec/es8326.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __SPACEMIT_ES8326_H__ +#define __SPACEMIT_ES8326_H__ + +#include + +#define ES8326_RESET 0x00 +#define ES8326_CLK_CTL 0x01 +#define ES8326_CLK_INV 0x02 +#define ES8326_CLK_RESAMPLE 0x03 +#define ES8326_CLK_DIV1 0x04 +#define ES8326_CLK_DIV2 0x05 +#define ES8326_CLK_DLL 0x06 +#define ES8326_CLK_MUX 0x07 +#define ES8326_CLK_ADC_SEL 0x08 +#define ES8326_CLK_DAC_SEL 0x09 +#define ES8326_CLK_ADC_OSR 0x0a +#define ES8326_CLK_DAC_OSR 0x0b +#define ES8326_CLK_DIV_CPC 0x0c +#define ES8326_CLK_DIV_BCLK 0x0d +#define ES8326_CLK_TRI 0x0e +#define ES8326_CLK_VMIDS1 0x10 +#define ES8326_CLK_VMIDS2 0x11 +#define ES8326_CLK_CAL_TIME 0x12 +#define ES8326_FMT 0x13 +#define ES8326_DAC_MUTE 0x14 +#define ES8326_ADC_MUTE 0x15 +#define ES8326_ANA_PDN 0x16 +#define ES8326_VMIDSEL 0x18 +#define ES8326_ANA_LP 0x19 +#define ES8326_ANA_MICBIAS 0x1b +#define ES8326_ANA_VSEL 0x1c +#define ES8326_VMIDLOW 0x22 +#define ES8326_PGAGAIN 0x23 +#define ES8326_HP_DRIVER 0x24 +#define ES8326_DAC2HPMIX 0x25 +#define ES8326_HP_VOL 0x26 +#define ES8326_HP_CAL 0x27 +#define ES8326_HP_DRIVER_REF 0x28 +#define ES8326_ADC1_SRC 0x2a +#define ES8326_ADC2_SRC 0x2b +#define ES8326_HP_OFFSET_CAL 0x4a +#define ES8326_HPL_OFFSET_INI 0x4b +#define ES8326_HPR_OFFSET_INI 0x4c +#define ES8326_DAC_DSM 0x4d +#define ES8326_DAC_RAMPRATE 0x4e +#define ES8326_DAC_VPPSCALE 0x4f +#define ES8326_DAC_VOL 0x50 +#define ES8326_DAC_CROSSTALK 0x55 +#define ES8326_HPJACK_TIMER 0x56 +#define ES8326_HPDET_TYPE 0x57 +#define ES8326_INT_SOURCE 0x58 +#define ES8326_INTOUT_IO 0x59 +#define ES8326_SDINOUT1_IO 0x5a +#define ES8326_SDINOUT23_IO 0x5b +#define ES8326_HP_MISC 0xf7 +#define ES8326_PULLUP_CTL 0xf9 +#define ES8326_HPDET_STA 0xfb +#define ES8326_CSM_MUTE_STA 0xfc +#define ES8326_CHIP_ID1 0xfd +#define ES8326_CHIP_ID2 0xfe +#define ES8326_CHIP_VERSION 0xff + +#define ES8326_CSM_ON RT_BIT(7) +#define ES8326_CLK_ON 0x7e +#define ES8326_S16_LE (3 << 2) +#define ES8326_DATA_LEN_MASK (7 << 2) +#define ES8326_MUTE_MASK (3 << 0) +#define ES8326_MUTE (3 << 0) +#define ES8326_MIC_SEL_MASK (3 << 4) +#define ES8326_MIC1_SEL RT_BIT(4) +#define ES8326_HP_OFF 0 +#define ES8326_HP_ON 0x77 +#define ES8326_HP_DET_SRC_PIN9 RT_BIT(4) +#define ES8326_HP_TYPE_AUTO RT_BIT(0) +#define ES8326_INT_SRC_PIN9 RT_BIT(3) +#define ES8326_IO_INPUT 0 +#define ES8326_IO_DMIC_CLK 9 +#define ES8326_SDINOUT1_SHIFT 4 +#define ES8326_HPINSERT_FLAG RT_BIT(1) +#define ES8326_VERSION_B 3 + +#define ES8326_ADC_AMIC 0x22 +#define ES8326_ADC_DMIC 0x44 + +#endif /* __SPACEMIT_ES8326_H__ */ diff --git a/bsp/spacemit/dm/audio/spacemit-audio.h b/bsp/spacemit/dm/audio/spacemit-audio.h new file mode 100644 index 000000000000..1367d40b2cd0 --- /dev/null +++ b/bsp/spacemit/dm/audio/spacemit-audio.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __SPACEMIT_AUDIO_H__ +#define __SPACEMIT_AUDIO_H__ + +#include +#include +#include + +struct spacemit_i2s; +struct spacemit_hdmi_audio; +struct es8326_codec; + +struct spacemit_audio_config +{ + rt_uint32_t samplerate; + rt_uint16_t channels; + rt_uint16_t samplebits; + rt_uint32_t mclk_fs; +}; + +struct spacemit_pcm +{ + struct rt_device *dev; + struct rt_ofw_node *np; + struct rt_dma_chan *tx; + struct rt_dma_chan *rx; + + rt_bool_t is_hdmi; + void *hdmi_buffer; + rt_ubase_t hdmi_dma; + rt_size_t hdmi_size; + + rt_list_t list; +}; + +struct spacemit_pcm *spacemit_pcm_find(struct rt_ofw_node *np); + +struct spacemit_i2s *spacemit_i2s_find(struct rt_ofw_node *np); +rt_err_t spacemit_i2s_configure(struct spacemit_i2s *i2s, + const struct spacemit_audio_config *config); +rt_err_t spacemit_i2s_start(struct spacemit_i2s *i2s); +rt_err_t spacemit_i2s_stop(struct spacemit_i2s *i2s); +rt_ubase_t spacemit_i2s_fifo_phys(struct spacemit_i2s *i2s); + +struct spacemit_hdmi_audio *spacemit_hdmi_audio_find(struct rt_ofw_node *np); +rt_err_t spacemit_hdmi_audio_start(struct spacemit_hdmi_audio *hdmi); +rt_err_t spacemit_hdmi_audio_stop(struct spacemit_hdmi_audio *hdmi); +rt_ubase_t spacemit_hdmi_audio_fifo_phys(struct spacemit_hdmi_audio *hdmi); +rt_bool_t spacemit_hdmi_audio_connected(struct spacemit_hdmi_audio *hdmi); + +struct es8326_codec *es8326_codec_find(struct rt_ofw_node *np); +rt_err_t es8326_codec_hw_params(struct es8326_codec *codec, + const struct spacemit_audio_config *config); +rt_err_t es8326_codec_start(struct es8326_codec *codec, int stream); +rt_err_t es8326_codec_stop(struct es8326_codec *codec, int stream); +rt_err_t es8326_codec_set_volume(struct es8326_codec *codec, int volume); +rt_err_t es8326_codec_set_mute(struct es8326_codec *codec, rt_bool_t mute); + +#endif /* __SPACEMIT_AUDIO_H__ */ diff --git a/bsp/spacemit/dm/audio/spacemit-snd-card.c b/bsp/spacemit/dm/audio/spacemit-snd-card.c new file mode 100644 index 000000000000..9d3290c22f30 --- /dev/null +++ b/bsp/spacemit/dm/audio/spacemit-snd-card.c @@ -0,0 +1,1087 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#define DBG_TAG "audio.card.spacemit" +#define DBG_LVL DBG_INFO +#include + +#include "spacemit-audio.h" + +#define CARD_PREFIX "simple-audio-card," +#define CARD_DAI "sound-dai" + +#define ANALOG_BLOCK_SIZE 4096 +#define ANALOG_BLOCK_COUNT 4 +#define ANALOG_BUFFER_SIZE (ANALOG_BLOCK_SIZE * ANALOG_BLOCK_COUNT) +#define CAPTURE_PERIOD_SIZE 2048 +#define CAPTURE_PERIOD_COUNT 4 +#define CAPTURE_BUFFER_SIZE (CAPTURE_PERIOD_SIZE * CAPTURE_PERIOD_COUNT) + +#define HDMI_PCM_BLOCK_SIZE (480 * 4) +#define HDMI_PCM_BLOCK_COUNT 4 +#define HDMI_PCM_BUFFER_SIZE (HDMI_PCM_BLOCK_SIZE * HDMI_PCM_BLOCK_COUNT) +#define HDMI_RAW_BLOCK_SIZE (HDMI_PCM_BLOCK_SIZE * 2) +#define HDMI_RAW_BUFFER_SIZE (HDMI_RAW_BLOCK_SIZE * HDMI_PCM_BLOCK_COUNT) + +#define AUDIO_DMA_BURST 32 +#define AUDIO_TX_THREAD_STACK 4096 +#define AUDIO_TX_THREAD_PRIO 12 +#define HDMI_SAMPLE_PRESENT RT_BIT(31) +#define HDMI_FRAME_START RT_BIT(30) +#define HDMI_PARITY RT_BIT(27) +#define HDMI_CHANNEL_STATUS RT_BIT(26) +#define HDMI_VALID RT_BIT(24) + +struct spacemit_audio_card +{ + struct rt_audio_device audio; + struct spacemit_audio_config config; + struct rt_device *dev; + + struct spacemit_i2s *i2s; + struct spacemit_hdmi_audio *hdmi; + struct es8326_codec *codec; + struct spacemit_pcm *pcm; + + void *playback_buffer; + rt_ubase_t playback_dma; + rt_size_t playback_size; + rt_size_t playback_block_size; + + void *capture_buffer; + rt_ubase_t capture_dma; + rt_size_t capture_pos; + + rt_bool_t is_hdmi; + rt_bool_t replay_started; + rt_bool_t record_started; + rt_bool_t tx_running; + rt_bool_t rx_running; + rt_bool_t tx_silent; + rt_bool_t tx_drain; + rt_bool_t tx_drain_timer_inited; + rt_bool_t muted; + rt_uint8_t volume; + rt_uint8_t iec_offset; + rt_uint8_t tx_primed_periods; + rt_uint32_t tx_done_count; + rt_uint32_t tx_service_count; + rt_bool_t tx_sem_inited; + rt_bool_t tx_thread_exit; + struct rt_semaphore tx_sem; + rt_thread_t tx_thread; + struct rt_timer tx_drain_timer; + char name[32]; +}; + +static void spacemit_hdmi_reformat(struct spacemit_audio_card *card, + rt_uint32_t *destination, const rt_int16_t *source, rt_size_t frames); + +static struct rt_ofw_node *spacemit_audio_parse_dai(struct rt_ofw_node *card_np, + const char *link_name) +{ + struct rt_ofw_node *link_np, *args_np; + struct rt_ofw_cell_args args; + + link_np = rt_ofw_get_child_by_tag(card_np, link_name); + if (!link_np) + { + return RT_NULL; + } + + if (rt_ofw_parse_phandle_cells(link_np, CARD_DAI, + "#sound-dai-cells", 0, &args)) + { + rt_ofw_node_put(link_np); + return RT_NULL; + } + + args_np = args.data; + rt_ofw_node_get(args_np); + rt_ofw_node_put(link_np); + + return args_np; +} + +static rt_err_t spacemit_audio_validate_config( + const struct rt_audio_configure *config) +{ + return config->samplerate == 48000 && config->channels == 2 && + config->samplebits == 16 ? RT_EOK : -RT_EINVAL; +} + +static rt_err_t spacemit_audio_apply_config(struct spacemit_audio_card *card) +{ + rt_err_t err; + + if (card->is_hdmi) + { + return RT_EOK; + } + + if ((err = spacemit_i2s_configure(card->i2s, &card->config))) + { + return err; + } + + return es8326_codec_hw_params(card->codec, &card->config); +} + +static rt_err_t spacemit_audio_getcaps(struct rt_audio_device *audio, + struct rt_audio_caps *caps) +{ + struct spacemit_audio_card *card = audio->parent.user_data; + + switch (caps->main_type) + { + case AUDIO_TYPE_QUERY: + caps->udata.mask = AUDIO_TYPE_OUTPUT | AUDIO_TYPE_MIXER; + if (!card->is_hdmi) + { + caps->udata.mask |= AUDIO_TYPE_INPUT; + } + break; + + case AUDIO_TYPE_OUTPUT: + case AUDIO_TYPE_INPUT: + if (caps->main_type == AUDIO_TYPE_INPUT && card->is_hdmi) + { + return -RT_ENOSYS; + } + switch (caps->sub_type) + { + case AUDIO_DSP_PARAM: + caps->udata.config.samplerate = card->config.samplerate; + caps->udata.config.channels = card->config.channels; + caps->udata.config.samplebits = card->config.samplebits; + break; + case AUDIO_DSP_SAMPLERATE: + caps->udata.config.samplerate = card->config.samplerate; + caps->udata.mask = AUDIO_SAMP_RATE_48K; + break; + case AUDIO_DSP_CHANNELS: + caps->udata.config.channels = card->config.channels; + break; + case AUDIO_DSP_SAMPLEBITS: + caps->udata.config.samplebits = card->config.samplebits; + break; + default: + return -RT_ENOSYS; + } + break; + + case AUDIO_TYPE_MIXER: + switch (caps->sub_type) + { + case AUDIO_MIXER_QUERY: + caps->udata.mask = AUDIO_MIXER_VOLUME | AUDIO_MIXER_MUTE; + break; + case AUDIO_MIXER_VOLUME: + caps->udata.value = card->volume; + break; + case AUDIO_MIXER_MUTE: + caps->udata.value = card->muted; + break; + default: + return -RT_ENOSYS; + } + break; + + default: + return -RT_ENOSYS; + } + + return RT_EOK; +} + +static rt_err_t spacemit_audio_configure(struct rt_audio_device *audio, + struct rt_audio_caps *caps) +{ + rt_err_t err; + struct spacemit_audio_card *card = audio->parent.user_data; + + switch (caps->main_type) + { + case AUDIO_TYPE_OUTPUT: + case AUDIO_TYPE_INPUT: + if (caps->main_type == AUDIO_TYPE_INPUT && card->is_hdmi) + { + return -RT_ENOSYS; + } + if (caps->sub_type != AUDIO_DSP_PARAM) + { + return -RT_ENOSYS; + } + if ((err = spacemit_audio_validate_config(&caps->udata.config))) + { + LOG_W("%s supports 48000 Hz, stereo, 16-bit PCM only", card->name); + return err; + } + card->config.samplerate = caps->udata.config.samplerate; + card->config.channels = caps->udata.config.channels; + card->config.samplebits = caps->udata.config.samplebits; + return spacemit_audio_apply_config(card); + + case AUDIO_TYPE_MIXER: + if (caps->sub_type == AUDIO_MIXER_VOLUME) + { + int volume = caps->udata.value; + + if (volume < AUDIO_VOLUME_MIN) + { + volume = AUDIO_VOLUME_MIN; + } + if (volume > AUDIO_VOLUME_MAX) + { + volume = AUDIO_VOLUME_MAX; + } + card->volume = volume; + return card->codec ? es8326_codec_set_volume(card->codec, volume) : RT_EOK; + } + if (caps->sub_type == AUDIO_MIXER_MUTE) + { + card->muted = !!caps->udata.value; + return card->codec ? es8326_codec_set_mute(card->codec, card->muted) : RT_EOK; + } + return -RT_ENOSYS; + + default: + return -RT_ENOSYS; + } +} + +static rt_err_t spacemit_audio_dma_prepare_tx(struct spacemit_audio_card *card, + rt_ubase_t source, rt_size_t length, rt_size_t period) +{ + rt_err_t err; + struct rt_dma_slave_config config = { 0 }; + struct rt_dma_slave_transfer transfer = { 0 }; + + config.direction = RT_DMA_MEM_TO_DEV; + config.src_addr = source; + config.dst_addr = card->is_hdmi ? + spacemit_hdmi_audio_fifo_phys(card->hdmi) : + spacemit_i2s_fifo_phys(card->i2s); + config.src_addr_width = RT_DMA_SLAVE_BUSWIDTH_4_BYTES; + config.dst_addr_width = RT_DMA_SLAVE_BUSWIDTH_4_BYTES; + config.src_maxburst = AUDIO_DMA_BURST; + config.dst_maxburst = AUDIO_DMA_BURST; + + if (card->is_hdmi) + { + LOG_D("%s: TX DMA config begin: src=%08lx dst=%08lx len=%u period=%u", + card->name, (unsigned long)source, + (unsigned long)config.dst_addr, + (unsigned int)length, (unsigned int)period); + } + if ((err = rt_dma_chan_config(card->pcm->tx, &config))) + { + if (card->is_hdmi) + { + LOG_E("%s: TX DMA config failed: %s", card->name, + rt_strerror(err)); + } + return err; + } + if (card->is_hdmi) + { + LOG_D("%s: TX DMA config done", card->name); + } + + transfer.src_addr = source; + transfer.dst_addr = config.dst_addr; + transfer.buffer_len = length; + transfer.period_len = period; + + if (card->is_hdmi) + { + LOG_D("%s: TX DMA prep begin", card->name); + } + if ((err = rt_dma_prep_cyclic(card->pcm->tx, &transfer))) + { + if (card->is_hdmi) + { + LOG_E("%s: TX DMA prep failed: %s", card->name, + rt_strerror(err)); + } + return err; + } + if (card->is_hdmi) + { + LOG_D("%s: TX DMA prep done, start begin", card->name); + } + + err = rt_dma_chan_start(card->pcm->tx); + if (card->is_hdmi) + { + if (err) + { + LOG_E("%s: TX DMA start failed: %s", card->name, + rt_strerror(err)); + } + else + { + LOG_D("%s: TX DMA start done", card->name); + } + } + + return err; +} + +static void spacemit_audio_drain_timer(void *parameter) +{ + struct spacemit_audio_card *card = parameter; + + if (card->replay_started && card->tx_drain) + { + rt_audio_tx_complete(&card->audio); + } +} + +static void spacemit_audio_start_drain_tx(struct spacemit_audio_card *card) +{ + rt_tick_t tick; + + if (!card->tx_drain_timer_inited) + { + return; + } + + tick = rt_tick_from_millisecond(10); + if (!tick) + { + tick = 1; + } + + card->tx_running = RT_TRUE; + card->tx_silent = RT_FALSE; + card->tx_drain = RT_TRUE; + rt_timer_control(&card->tx_drain_timer, RT_TIMER_CTRL_SET_TIME, &tick); + rt_timer_start(&card->tx_drain_timer); +} + +static void spacemit_audio_stop_drain_tx(struct spacemit_audio_card *card) +{ + if (card->tx_drain_timer_inited) + { + rt_timer_stop(&card->tx_drain_timer); + } + card->tx_drain = RT_FALSE; +} + +static void spacemit_audio_hdmi_silence(struct spacemit_audio_card *card) +{ + rt_memset(card->pcm->hdmi_buffer, 0, HDMI_RAW_BUFFER_SIZE); + rt_hw_wmb(); +} + +static void spacemit_audio_tx_worker(void *parameter) +{ + struct spacemit_audio_card *card = parameter; + + while (!card->tx_thread_exit) + { + rt_sem_take(&card->tx_sem, RT_WAITING_FOREVER); + + if (card->tx_thread_exit) + { + break; + } + if (card->replay_started && !card->tx_silent) + { + card->tx_service_count++; + if (card->tx_service_count <= 4 || + !(card->tx_service_count % 100)) + { + LOG_D("%s: TX service #%u", card->name, + card->tx_service_count); + } + rt_audio_tx_complete(&card->audio); + } + } +} + +static rt_err_t spacemit_audio_ensure_tx_thread(struct spacemit_audio_card *card) +{ + if (card->tx_thread) + { + return RT_EOK; + } + + if (!card->tx_sem_inited) + { + return -RT_ERROR; + } + + card->tx_thread_exit = RT_FALSE; + card->tx_thread = rt_thread_create("audtx", + spacemit_audio_tx_worker, card, + AUDIO_TX_THREAD_STACK, AUDIO_TX_THREAD_PRIO, 10); + if (!card->tx_thread) + { + return -RT_ENOMEM; + } + + return rt_thread_startup(card->tx_thread); +} + +static rt_err_t spacemit_audio_start_silent_tx(struct spacemit_audio_card *card) +{ + rt_err_t err; + + rt_memset(card->playback_buffer, 0, card->playback_size); + if ((err = spacemit_audio_dma_prepare_tx(card, card->playback_dma, + card->playback_size, card->playback_block_size))) + { + return err; + } + + card->tx_running = RT_TRUE; + card->tx_silent = RT_TRUE; + return RT_EOK; +} + +static rt_err_t spacemit_audio_start_rx(struct spacemit_audio_card *card) +{ + rt_err_t err; + struct rt_dma_slave_config config = { 0 }; + struct rt_dma_slave_transfer transfer = { 0 }; + + config.direction = RT_DMA_DEV_TO_MEM; + config.src_addr = spacemit_i2s_fifo_phys(card->i2s); + config.dst_addr = card->capture_dma; + config.src_addr_width = RT_DMA_SLAVE_BUSWIDTH_4_BYTES; + config.dst_addr_width = RT_DMA_SLAVE_BUSWIDTH_4_BYTES; + config.src_maxburst = AUDIO_DMA_BURST; + config.dst_maxburst = AUDIO_DMA_BURST; + + if ((err = rt_dma_chan_config(card->pcm->rx, &config))) + { + return err; + } + + transfer.src_addr = config.src_addr; + transfer.dst_addr = card->capture_dma; + transfer.buffer_len = CAPTURE_BUFFER_SIZE; + transfer.period_len = CAPTURE_PERIOD_SIZE; + + if ((err = rt_dma_prep_cyclic(card->pcm->rx, &transfer))) + { + return err; + } + if ((err = rt_dma_chan_start(card->pcm->rx))) + { + return err; + } + + card->capture_pos = 0; + card->rx_running = RT_TRUE; + return RT_EOK; +} + +static rt_err_t spacemit_audio_init(struct rt_audio_device *audio) +{ + struct spacemit_audio_card *card = audio->parent.user_data; + + return spacemit_audio_apply_config(card); +} + +static rt_err_t spacemit_audio_start(struct rt_audio_device *audio, int stream) +{ + rt_err_t err; + rt_bool_t codec_started = RT_FALSE; + rt_bool_t silent_started = RT_FALSE; + rt_bool_t was_silent = RT_FALSE; + struct spacemit_audio_card *card = audio->parent.user_data; + + if (stream == AUDIO_STREAM_REPLAY) + { + if (card->replay_started) + { + return RT_EOK; + } + + if (card->tx_running && card->tx_silent) + { + was_silent = RT_TRUE; + rt_dma_chan_stop(card->pcm->tx); + card->tx_running = RT_FALSE; + card->tx_silent = RT_FALSE; + } + + if (card->is_hdmi) + { + if ((err = spacemit_hdmi_audio_start(card->hdmi))) + { + return err; + } + } + else + { + if ((err = es8326_codec_start(card->codec, stream))) + { + goto _restore_silent_tx; + } + codec_started = RT_TRUE; + if ((err = spacemit_i2s_start(card->i2s))) + { + es8326_codec_stop(card->codec, stream); + goto _restore_silent_tx; + } + } + + card->iec_offset = 0; + card->replay_started = RT_TRUE; + card->tx_drain = RT_FALSE; + card->tx_primed_periods = 0; + card->tx_done_count = 0; + card->tx_service_count = 0; + if (audio->replay) + { + audio->replay->read_index = 0; + } + if (card->is_hdmi) + { + spacemit_audio_hdmi_silence(card); + } + + /* Prime the first hardware period from a playback worker thread. */ + if ((err = spacemit_audio_ensure_tx_thread(card))) + { + card->replay_started = RT_FALSE; + goto _stop_playback; + } + if (card->is_hdmi) + { + for (int i = 0; i < HDMI_PCM_BLOCK_COUNT; ++i) + { + rt_sem_release(&card->tx_sem); + } + } + else + { + rt_sem_release(&card->tx_sem); + } + return RT_EOK; + } + + if (stream == AUDIO_STREAM_RECORD && !card->is_hdmi) + { + if (card->record_started) + { + return RT_EOK; + } + if (!card->tx_running && + (err = spacemit_audio_start_silent_tx(card))) + { + return err; + } + silent_started = !card->replay_started && card->tx_silent; + if ((err = spacemit_audio_start_rx(card))) + { + goto _stop_silent_tx; + } + if ((err = es8326_codec_start(card->codec, stream))) + { + goto _stop_rx; + } + codec_started = RT_TRUE; + if ((err = spacemit_i2s_start(card->i2s))) + { + goto _stop_codec; + } + card->record_started = RT_TRUE; + return RT_EOK; + } + + return -RT_EINVAL; + +_stop_playback: + if (card->is_hdmi) + { + spacemit_hdmi_audio_stop(card->hdmi); + } + else + { + if (codec_started) + { + es8326_codec_stop(card->codec, stream); + } + spacemit_i2s_stop(card->i2s); + } + return err; + +_stop_codec: + if (codec_started) + { + es8326_codec_stop(card->codec, stream); + } +_stop_rx: + if (card->rx_running) + { + rt_dma_chan_stop(card->pcm->rx); + card->rx_running = RT_FALSE; + } +_stop_silent_tx: + if (silent_started && card->tx_running) + { + rt_dma_chan_stop(card->pcm->tx); + card->tx_running = RT_FALSE; + card->tx_silent = RT_FALSE; + } + return err; + +_restore_silent_tx: + if (was_silent && spacemit_audio_start_silent_tx(card)) + { + LOG_E("%s: failed to restore capture clock DMA", card->name); + } + return err; +} + +static rt_err_t spacemit_audio_stop(struct rt_audio_device *audio, int stream) +{ + rt_err_t err = RT_EOK; + struct spacemit_audio_card *card = audio->parent.user_data; + + if (stream == AUDIO_STREAM_REPLAY && card->replay_started) + { + if (card->tx_drain) + { + spacemit_audio_stop_drain_tx(card); + } + + if (card->tx_running) + { + rt_dma_chan_stop(card->pcm->tx); + card->tx_running = RT_FALSE; + } + card->tx_silent = RT_FALSE; + card->tx_primed_periods = 0; + if (audio->replay) + { + audio->replay->read_index = 0; + } + card->replay_started = RT_FALSE; + + if (card->is_hdmi) + { + err = spacemit_hdmi_audio_stop(card->hdmi); + } + else + { + es8326_codec_stop(card->codec, stream); + spacemit_i2s_stop(card->i2s); + if (card->record_started) + { + err = spacemit_audio_start_silent_tx(card); + } + } + return err; + } + + if (stream == AUDIO_STREAM_RECORD && card->record_started) + { + if (card->rx_running) + { + rt_dma_chan_stop(card->pcm->rx); + card->rx_running = RT_FALSE; + } + if (!card->replay_started && card->tx_running) + { + rt_dma_chan_stop(card->pcm->tx); + card->tx_running = RT_FALSE; + card->tx_silent = RT_FALSE; + } + card->record_started = RT_FALSE; + es8326_codec_stop(card->codec, stream); + return spacemit_i2s_stop(card->i2s); + } + + return RT_EOK; +} + +static rt_uint32_t spacemit_hdmi_parity(rt_uint32_t sample) +{ + sample ^= sample >> 16; + sample ^= sample >> 8; + sample ^= sample >> 4; + sample &= 0xf; + return (0x6996 >> sample) & 1; +} + +static void spacemit_hdmi_reformat(struct spacemit_audio_card *card, + rt_uint32_t *destination, const rt_int16_t *source, rt_size_t frames) +{ + while (frames--) + { + for (int channel = 0; channel < 2; ++channel) + { + rt_uint32_t sample = (rt_uint16_t)*source++ << 8; + + sample |= HDMI_SAMPLE_PRESENT | HDMI_VALID; + if (!card->iec_offset) + { + sample |= HDMI_FRAME_START; + } + if (card->iec_offset == 25 || card->iec_offset == 32) + { + sample |= HDMI_CHANNEL_STATUS; + } + sample |= spacemit_hdmi_parity(sample) << 27; + *destination++ = sample; + } + + if (++card->iec_offset == 192) + { + card->iec_offset = 0; + } + } +} + +static rt_ssize_t spacemit_audio_transmit(struct rt_audio_device *audio, + const void *write_buf, void *read_buf, rt_size_t size) +{ + rt_err_t err; + rt_ubase_t offset; + struct spacemit_audio_card *card = audio->parent.user_data; + + RT_UNUSED(read_buf); + + if (!card->replay_started || size != card->playback_block_size) + { + return 0; + } + + offset = (const rt_uint8_t *)write_buf - + (const rt_uint8_t *)card->playback_buffer; + if (offset >= card->playback_size) + { + return -RT_EINVAL; + } + + if (card->is_hdmi) + { + spacemit_hdmi_reformat(card, + (rt_uint32_t *)((rt_uint8_t *)card->pcm->hdmi_buffer + offset * 2), + write_buf, size / 4); + rt_hw_wmb(); + } + + if (!card->tx_running) + { + rt_ubase_t dma = card->is_hdmi ? card->pcm->hdmi_dma : card->playback_dma; + rt_size_t length = card->is_hdmi ? HDMI_RAW_BUFFER_SIZE : card->playback_size; + rt_size_t period = card->is_hdmi ? HDMI_RAW_BLOCK_SIZE : card->playback_block_size; + + if (card->is_hdmi && ++card->tx_primed_periods < HDMI_PCM_BLOCK_COUNT) + { + return size; + } + + card->tx_done_count = 0; + card->tx_running = RT_TRUE; + card->tx_silent = RT_FALSE; + if ((err = spacemit_audio_dma_prepare_tx(card, dma, length, period))) + { + card->tx_running = RT_FALSE; + card->tx_primed_periods = 0; + LOG_E("%s: TX DMA start failed: %s", card->name, rt_strerror(err)); + LOG_D("%s: drain playback queue without hardware DMA", card->name); + spacemit_audio_start_drain_tx(card); + return size; + } + } + + return size; +} + +static void spacemit_audio_buffer_info(struct rt_audio_device *audio, + struct rt_audio_buf_info *info) +{ + struct spacemit_audio_card *card = audio->parent.user_data; + + info->buffer = card->playback_buffer; + info->block_size = card->playback_block_size; + info->block_count = card->is_hdmi ? HDMI_PCM_BLOCK_COUNT : ANALOG_BLOCK_COUNT; + info->total_size = card->playback_size; +} + +static const struct rt_audio_ops spacemit_audio_ops = +{ + .getcaps = spacemit_audio_getcaps, + .configure = spacemit_audio_configure, + .init = spacemit_audio_init, + .start = spacemit_audio_start, + .stop = spacemit_audio_stop, + .transmit = spacemit_audio_transmit, + .buffer_info = spacemit_audio_buffer_info, +}; + +static void spacemit_audio_tx_done(struct rt_dma_chan *channel, rt_size_t size) +{ + struct spacemit_audio_card *card = channel->priv; + + RT_UNUSED(size); + + if (card->replay_started && !card->tx_silent) + { + card->tx_done_count++; + if (card->tx_done_count <= 4 || !(card->tx_done_count % 100)) + { + LOG_D("%s: TX period done #%u", card->name, card->tx_done_count); + } + if (card->tx_sem_inited) + { + rt_sem_release(&card->tx_sem); + } + } +} + +static void spacemit_audio_rx_done(struct rt_dma_chan *channel, rt_size_t size) +{ + struct spacemit_audio_card *card = channel->priv; + + RT_UNUSED(size); + + if (card->record_started) + { + rt_audio_rx_done(&card->audio, + (rt_uint8_t *)card->capture_buffer + card->capture_pos, + CAPTURE_PERIOD_SIZE); + card->capture_pos += CAPTURE_PERIOD_SIZE; + card->capture_pos %= CAPTURE_BUFFER_SIZE; + } +} + +static void spacemit_audio_card_free(struct spacemit_audio_card *card) +{ + if (!card) + { + return; + } + + if (card->capture_buffer) + { + rt_dma_free_coherent(card->dev, CAPTURE_BUFFER_SIZE, + card->capture_buffer, card->capture_dma); + } + if (card->tx_drain_timer_inited) + { + rt_timer_stop(&card->tx_drain_timer); + rt_timer_detach(&card->tx_drain_timer); + } + if (card->tx_thread) + { + card->tx_thread_exit = RT_TRUE; + rt_sem_release(&card->tx_sem); + rt_thread_delete(card->tx_thread); + } + if (card->tx_sem_inited) + { + rt_sem_detach(&card->tx_sem); + } + if (card->playback_buffer) + { + rt_dma_free_coherent(card->dev, card->playback_size, + card->playback_buffer, card->playback_dma); + } + rt_free(card); +} + +static rt_err_t spacemit_audio_card_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + rt_uint32_t mclk_fs = 64; + rt_uint32_t flags; + const char *name = "spacemit-audio"; + struct rt_device *dev = &pdev->parent; + struct rt_ofw_node *cpu_np = RT_NULL, *plat_np = RT_NULL, *codec_np = RT_NULL; + struct spacemit_audio_card *card = rt_calloc(1, sizeof(*card)); + + if (!card) + { + return -RT_ENOMEM; + } + + card->dev = dev; + card->volume = 70; + card->config.samplerate = 48000; + card->config.channels = 2; + card->config.samplebits = 16; + rt_ofw_prop_read_string(dev->ofw_node, CARD_PREFIX "name", &name); + rt_strncpy(card->name, name, sizeof(card->name) - 1); + if (rt_ofw_prop_read_u32(dev->ofw_node, "spacemit,mclk-fs", &mclk_fs)) + { + rt_ofw_prop_read_u32(dev->ofw_node, CARD_PREFIX "mclk-fs", &mclk_fs); + } + card->config.mclk_fs = mclk_fs; + + cpu_np = spacemit_audio_parse_dai(dev->ofw_node, CARD_PREFIX "cpu"); + plat_np = spacemit_audio_parse_dai(dev->ofw_node, CARD_PREFIX "plat"); + codec_np = spacemit_audio_parse_dai(dev->ofw_node, CARD_PREFIX "codec"); + if (!cpu_np || !plat_np) + { + err = -RT_EINVAL; + LOG_E("%s: missing CPU or platform DAI", card->name); + goto _fail; + } + + card->pcm = spacemit_pcm_find(plat_np); + card->is_hdmi = rt_ofw_node_is_compatible(cpu_np, + "spacemit,spacemit-snd-sspa"); + if (!card->pcm) + { + err = -RT_ENOSYS; + LOG_E("%s: DMA platform is not ready", card->name); + goto _fail; + } + + if (card->is_hdmi) + { + card->hdmi = spacemit_hdmi_audio_find(cpu_np); + if (!card->hdmi || !card->pcm->is_hdmi || + card->pcm->hdmi_size < HDMI_RAW_BUFFER_SIZE) + { + err = -RT_ENOSYS; + LOG_E("%s: HDMI audio resources are not ready", card->name); + goto _fail; + } + card->playback_size = HDMI_PCM_BUFFER_SIZE; + card->playback_block_size = HDMI_PCM_BLOCK_SIZE; + flags = RT_DEVICE_FLAG_WRONLY; + } + else + { + card->i2s = spacemit_i2s_find(cpu_np); + card->codec = es8326_codec_find(codec_np); + if (!card->i2s || !card->codec || card->pcm->is_hdmi || !card->pcm->rx) + { + err = -RT_ENOSYS; + LOG_E("%s: I2S or ES8326 is not ready", card->name); + goto _fail; + } + card->playback_size = ANALOG_BUFFER_SIZE; + card->playback_block_size = ANALOG_BLOCK_SIZE; + flags = RT_DEVICE_FLAG_RDWR; + } + + card->playback_buffer = rt_dma_alloc_coherent(dev, card->playback_size, + &card->playback_dma); + if (!card->playback_buffer) + { + err = -RT_ENOMEM; + goto _fail; + } + rt_memset(card->playback_buffer, 0, card->playback_size); + + if (!card->is_hdmi) + { + card->capture_buffer = rt_dma_alloc_coherent(dev, CAPTURE_BUFFER_SIZE, + &card->capture_dma); + if (!card->capture_buffer) + { + err = -RT_ENOMEM; + goto _fail; + } + rt_memset(card->capture_buffer, 0, CAPTURE_BUFFER_SIZE); + } + + card->audio.ops = (struct rt_audio_ops *)&spacemit_audio_ops; + card->audio.parent.user_data = card; + rt_timer_init(&card->tx_drain_timer, "auddrn", + spacemit_audio_drain_timer, card, + rt_tick_from_millisecond(10), + RT_TIMER_FLAG_PERIODIC | RT_TIMER_FLAG_SOFT_TIMER); + card->tx_drain_timer_inited = RT_TRUE; + rt_sem_init(&card->tx_sem, "audtx", 0, RT_IPC_FLAG_PRIO); + card->tx_sem_inited = RT_TRUE; + + if ((err = rt_audio_register(&card->audio, card->name, flags, card))) + { + if (rt_device_find(card->name) == &card->audio.parent) + { + rt_device_unregister(&card->audio.parent); + } + goto _fail; + } + card->pcm->tx->callback = spacemit_audio_tx_done; + card->pcm->tx->priv = card; + if (card->pcm->rx) + { + card->pcm->rx->callback = spacemit_audio_rx_done; + card->pcm->rx->priv = card; + } + + dev->user_data = card; + rt_dm_dev_bind_fwdata(dev, RT_NULL, card); + rt_ofw_node_put(cpu_np); + rt_ofw_node_put(plat_np); + rt_ofw_node_put(codec_np); + + LOG_I("%s: 48 kHz stereo 16-bit %s audio ready", card->name, + card->is_hdmi ? "HDMI" : "ES8326"); + return RT_EOK; + +_fail: + rt_ofw_node_put(cpu_np); + rt_ofw_node_put(plat_np); + rt_ofw_node_put(codec_np); + spacemit_audio_card_free(card); + return err; +} + +static rt_err_t spacemit_audio_card_remove(struct rt_platform_device *pdev) +{ + struct spacemit_audio_card *card = pdev->parent.user_data; + + if (!card) + { + return RT_EOK; + } + if (card->replay_started || card->record_started) + { + return -RT_EBUSY; + } + + rt_device_unregister(&card->audio.parent); + rt_dm_dev_unbind_fwdata(&pdev->parent, RT_NULL); + card->pcm->tx->callback = RT_NULL; + card->pcm->tx->priv = RT_NULL; + if (card->pcm->rx) + { + card->pcm->rx->callback = RT_NULL; + card->pcm->rx->priv = RT_NULL; + } + spacemit_audio_card_free(card); + + return RT_EOK; +} + +static const struct rt_ofw_node_id spacemit_audio_card_ofw_ids[] = +{ + { .compatible = "spacemit,simple-audio-card" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_audio_card_driver = +{ + .name = "spacemit-audio-card", + .ids = spacemit_audio_card_ofw_ids, + .probe = spacemit_audio_card_probe, + .remove = spacemit_audio_card_remove, +}; + +static int spacemit_audio_card_register(void) +{ + rt_platform_driver_register(&spacemit_audio_card_driver); + return 0; +} +INIT_COMPONENT_EXPORT(spacemit_audio_card_register); diff --git a/bsp/spacemit/dm/audio/spacemit-snd-i2s.c b/bsp/spacemit/dm/audio/spacemit-snd-i2s.c new file mode 100644 index 000000000000..1ed6b59bc7fc --- /dev/null +++ b/bsp/spacemit/dm/audio/spacemit-snd-i2s.c @@ -0,0 +1,376 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#define DBG_TAG "i2s.spacemit" +#define DBG_LVL DBG_INFO +#include + +#include "spacemit-audio.h" +#include "spacemit-snd-i2s.h" + +#define K1_APBC_BASE 0xd4015000UL +#define K1_APBC_SIZE 0x100 +#define K1_APBC_SSPA0 0x80 +#define K1_APBC_SSPA1 0x84 +#define K1_APBC_SSPA_AUDIO_MODE RT_BIT(3) + +#define K1_MPMU_BASE 0xd4050000UL +#define K1_MPMU_SIZE 0x100 +#define K1_MPMU_SYSCLK_PRE_CTRL 0x08 +#define K1_MPMU_ISCCR1 0x44 +#define K1_MPMU_SYSCLK_BASE_156M RT_BIT(30) +#define K1_MPMU_I2S_BCLK_ENABLE RT_BIT(29) + +struct spacemit_i2s +{ + struct rt_device *dev; + struct rt_ofw_node *np; + + void *regs; + void *apbc; + void *mpmu; + rt_ubase_t phys; + + struct rt_clk *clk; + struct rt_reset_control *reset; + struct spacemit_audio_config config; + + int port; + int users; + rt_list_t list; +}; + +static rt_list_t i2s_nodes = RT_LIST_OBJECT_INIT(i2s_nodes); +static RT_DEFINE_SPINLOCK(i2s_nodes_lock); + +static rt_uint32_t i2s_read(struct spacemit_i2s *i2s, rt_ubase_t reg) +{ + return HWREG32((char *)i2s->regs + reg); +} + +static void i2s_write(struct spacemit_i2s *i2s, rt_ubase_t reg, rt_uint32_t value) +{ + HWREG32((char *)i2s->regs + reg) = value; +} + +struct spacemit_i2s *spacemit_i2s_find(struct rt_ofw_node *np) +{ + struct spacemit_i2s *i2s; + + rt_spin_lock(&i2s_nodes_lock); + rt_list_for_each_entry(i2s, &i2s_nodes, list) + { + if (i2s->np == np) + { + rt_spin_unlock(&i2s_nodes_lock); + return i2s; + } + } + rt_spin_unlock(&i2s_nodes_lock); + + return RT_NULL; +} + +static rt_err_t spacemit_i2s_set_clock(struct spacemit_i2s *i2s, + const struct spacemit_audio_config *config) +{ + rt_uint32_t divider, mclk_fs, ratio, target, value; + rt_uint64_t bclk, mclk; + + bclk = (rt_uint64_t)config->samplerate * config->channels * config->samplebits; + mclk_fs = config->mclk_fs ? config->mclk_fs : 64; + mclk = (rt_uint64_t)config->samplerate * mclk_fs; + + if (!bclk || mclk > 0xffffffffU || mclk % bclk) + { + return -RT_EINVAL; + } + + switch (mclk_fs) + { + case 64: + divider = 326; + break; + case 128: + divider = 652; + break; + case 256: + divider = 1304; + break; + default: + return -RT_EINVAL; + } + + ratio = (rt_uint32_t)(mclk / bclk); + switch (ratio) + { + case 2: + ratio = 0; + break; + case 4: + ratio = 1; + break; + case 6: + ratio = 2; + break; + case 8: + ratio = 3; + break; + default: + return -RT_EINVAL; + } + + target = K1_MPMU_SYSCLK_BASE_156M | (ratio << 27) | + (divider << 15) | 32600; + value = HWREG32((char *)i2s->mpmu + K1_MPMU_ISCCR1); + value &= ~0x5fffffffU; + HWREG32((char *)i2s->mpmu + K1_MPMU_ISCCR1) = value | target; + + value = HWREG32((char *)i2s->mpmu + K1_MPMU_SYSCLK_PRE_CTRL); + HWREG32((char *)i2s->mpmu + K1_MPMU_SYSCLK_PRE_CTRL) = + value | K1_MPMU_I2S_BCLK_ENABLE; + + if (!rt_is_err_or_null(i2s->clk)) + { + rt_clk_set_rate(i2s->clk, (rt_uint32_t)bclk); + } + + return RT_EOK; +} + +rt_err_t spacemit_i2s_configure(struct spacemit_i2s *i2s, + const struct spacemit_audio_config *config) +{ + rt_uint32_t fifo, psp, top; + rt_err_t err; + + if (!i2s || !config || config->samplerate != 48000 || + config->channels != 2 || config->samplebits != 16) + { + return -RT_EINVAL; + } + + if (i2s->users) + { + return rt_memcmp(&i2s->config, config, sizeof(*config)) ? + -RT_EBUSY : RT_EOK; + } + + if ((err = spacemit_i2s_set_clock(i2s, config))) + { + return err; + } + + top = SSPA_TOP_TRAIL_DMA | SSPA_TOP_DATA_WIDTH_32 | SSPA_TOP_FRAME_PSP; + fifo = SSPA_FIFO_RX_DMA_REQ | SSPA_FIFO_TX_DMA_REQ | + SSPA_FIFO_RX_THRESHOLD(15) | SSPA_FIFO_TX_THRESHOLD(15); + psp = SSPA_PSP_FRAME_WIDTH(16) | SSPA_PSP_FRAME_SYNC_RELATIVE | + SSPA_PSP_FRAME_POLARITY; + + i2s_write(i2s, SSPA_TOP_CTRL, top); + i2s_write(i2s, SSPA_FIFO_CTRL, fifo); + i2s_write(i2s, SSPA_INT_EN, 0); + i2s_write(i2s, SSPA_TIMEOUT, 0); + i2s_write(i2s, SSPA_PSP_CTRL, psp); + i2s_write(i2s, SSPA_NETWORK_CTRL, 0); + + i2s->config = *config; + + return RT_EOK; +} + +rt_err_t spacemit_i2s_start(struct spacemit_i2s *i2s) +{ + rt_uint32_t value; + + if (!i2s) + { + return -RT_EINVAL; + } + + if (!i2s->users++) + { + value = i2s_read(i2s, SSPA_TOP_CTRL); + i2s_write(i2s, SSPA_TOP_CTRL, value | SSPA_TOP_ENABLE); + } + + return RT_EOK; +} + +rt_err_t spacemit_i2s_stop(struct spacemit_i2s *i2s) +{ + rt_uint32_t value; + + if (!i2s) + { + return -RT_EINVAL; + } + + if (i2s->users > 0 && !--i2s->users) + { + value = i2s_read(i2s, SSPA_TOP_CTRL); + i2s_write(i2s, SSPA_TOP_CTRL, value & ~SSPA_TOP_ENABLE); + } + + return RT_EOK; +} + +rt_ubase_t spacemit_i2s_fifo_phys(struct spacemit_i2s *i2s) +{ + return i2s ? i2s->phys + SSPA_DATA : 0; +} + +static void spacemit_i2s_free(struct spacemit_i2s *i2s) +{ + if (!i2s) + { + return; + } + + if (!rt_is_err_or_null(i2s->reset)) + { + rt_reset_control_assert(i2s->reset); + rt_reset_control_put(i2s->reset); + } + if (!rt_is_err_or_null(i2s->clk)) + { + rt_clk_disable_unprepare(i2s->clk); + rt_clk_put(i2s->clk); + } + if (i2s->regs) + { + rt_iounmap(i2s->regs); + } + if (i2s->apbc) + { + rt_iounmap(i2s->apbc); + } + if (i2s->mpmu) + { + rt_iounmap(i2s->mpmu); + } + + rt_free(i2s); +} + +static rt_err_t spacemit_i2s_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + rt_uint64_t phys; + rt_uint32_t apbc_offset, value; + struct rt_device *dev = &pdev->parent; + struct spacemit_i2s *i2s = rt_calloc(1, sizeof(*i2s)); + + if (!i2s) + { + return -RT_ENOMEM; + } + + i2s->dev = dev; + i2s->np = dev->ofw_node; + i2s->regs = rt_dm_dev_iomap(dev, 0); + if (!i2s->regs || rt_dm_dev_get_address(dev, 0, &phys, RT_NULL)) + { + err = -RT_EIO; + goto _fail; + } + i2s->phys = (rt_ubase_t)phys; + i2s->port = phys == 0xd4026000UL ? 0 : 1; + + i2s->apbc = rt_ioremap((void *)K1_APBC_BASE, K1_APBC_SIZE); + i2s->mpmu = rt_ioremap((void *)K1_MPMU_BASE, K1_MPMU_SIZE); + if (!i2s->apbc || !i2s->mpmu) + { + err = -RT_EIO; + goto _fail; + } + + i2s->clk = rt_clk_get_by_name(dev, "sspa-clk"); + if (rt_is_err(i2s->clk)) + { + err = rt_ptr_err(i2s->clk); + goto _fail; + } + if ((err = rt_clk_prepare_enable(i2s->clk))) + { + goto _fail; + } + + i2s->reset = rt_reset_control_get_by_name(dev, "sspa-rst"); + if (rt_is_err(i2s->reset)) + { + err = rt_ptr_err(i2s->reset); + goto _fail; + } + if ((err = rt_reset_control_deassert(i2s->reset))) + { + goto _fail; + } + + apbc_offset = i2s->port ? K1_APBC_SSPA1 : K1_APBC_SSPA0; + value = HWREG32((char *)i2s->apbc + apbc_offset); + HWREG32((char *)i2s->apbc + apbc_offset) = value | K1_APBC_SSPA_AUDIO_MODE; + + rt_spin_lock(&i2s_nodes_lock); + rt_list_insert_before(&i2s_nodes, &i2s->list); + rt_spin_unlock(&i2s_nodes_lock); + + dev->user_data = i2s; + rt_dm_dev_bind_fwdata(dev, RT_NULL, i2s); + + LOG_D("%s: I2S%d controller ready", rt_dm_dev_get_name(dev), i2s->port); + + return RT_EOK; + +_fail: + spacemit_i2s_free(i2s); + return err; +} + +static rt_err_t spacemit_i2s_remove(struct rt_platform_device *pdev) +{ + struct spacemit_i2s *i2s = pdev->parent.user_data; + + if (!i2s) + { + return RT_EOK; + } + + rt_spin_lock(&i2s_nodes_lock); + rt_list_remove(&i2s->list); + rt_spin_unlock(&i2s_nodes_lock); + + rt_dm_dev_unbind_fwdata(&pdev->parent, RT_NULL); + spacemit_i2s_free(i2s); + + return RT_EOK; +} + +static const struct rt_ofw_node_id spacemit_i2s_ofw_ids[] = +{ + { .compatible = "spacemit,spacemit-i2s0" }, + { .compatible = "spacemit,spacemit-i2s1" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_i2s_driver = +{ + .name = "spacemit-i2s", + .ids = spacemit_i2s_ofw_ids, + .probe = spacemit_i2s_probe, + .remove = spacemit_i2s_remove, +}; + +static int spacemit_i2s_register(void) +{ + rt_platform_driver_register(&spacemit_i2s_driver); + return 0; +} +INIT_DEVICE_EXPORT(spacemit_i2s_register); diff --git a/bsp/spacemit/dm/audio/spacemit-snd-i2s.h b/bsp/spacemit/dm/audio/spacemit-snd-i2s.h new file mode 100644 index 000000000000..c428b4f2c62e --- /dev/null +++ b/bsp/spacemit/dm/audio/spacemit-snd-i2s.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __SPACEMIT_SND_I2S_H__ +#define __SPACEMIT_SND_I2S_H__ + +#include + +#define SSPA_TOP_CTRL 0x00 +#define SSPA_FIFO_CTRL 0x04 +#define SSPA_INT_EN 0x08 +#define SSPA_TIMEOUT 0x0c +#define SSPA_DATA 0x10 +#define SSPA_STATUS 0x14 +#define SSPA_PSP_CTRL 0x18 +#define SSPA_NETWORK_CTRL 0x1c + +#define SSPA_TOP_TRAIL_DMA RT_BIT(13) +#define SSPA_TOP_DATA_WIDTH_MASK (0x1fU << 5) +#define SSPA_TOP_DATA_WIDTH_32 (0x1fU << 5) +#define SSPA_TOP_FRAME_PSP (0x3U << 1) +#define SSPA_TOP_ENABLE RT_BIT(0) + +#define SSPA_FIFO_RX_DMA_REQ RT_BIT(11) +#define SSPA_FIFO_TX_DMA_REQ RT_BIT(10) +#define SSPA_FIFO_RX_THRESHOLD(v) ((v) << 5) +#define SSPA_FIFO_TX_THRESHOLD(v) (v) + +#define SSPA_PSP_FRAME_WIDTH(v) ((v) << 12) +#define SSPA_PSP_FRAME_POLARITY RT_BIT(4) +#define SSPA_PSP_FRAME_SYNC_RELATIVE RT_BIT(3) + +#endif /* __SPACEMIT_SND_I2S_H__ */ diff --git a/bsp/spacemit/dm/audio/spacemit-snd-pcm-dma.c b/bsp/spacemit/dm/audio/spacemit-snd-pcm-dma.c new file mode 100644 index 000000000000..b90f6341985c --- /dev/null +++ b/bsp/spacemit/dm/audio/spacemit-snd-pcm-dma.c @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#define DBG_TAG "audio.pcm.spacemit" +#define DBG_LVL DBG_INFO +#include + +#include "spacemit-audio.h" + +static rt_list_t pcm_nodes = RT_LIST_OBJECT_INIT(pcm_nodes); +static RT_DEFINE_SPINLOCK(pcm_nodes_lock); + +struct spacemit_pcm *spacemit_pcm_find(struct rt_ofw_node *np) +{ + struct spacemit_pcm *pcm; + + rt_spin_lock(&pcm_nodes_lock); + rt_list_for_each_entry(pcm, &pcm_nodes, list) + { + if (pcm->np == np) + { + rt_spin_unlock(&pcm_nodes_lock); + return pcm; + } + } + rt_spin_unlock(&pcm_nodes_lock); + + return RT_NULL; +} + +static void spacemit_pcm_free(struct spacemit_pcm *pcm) +{ + if (!pcm) + { + return; + } + + if (!rt_is_err_or_null(pcm->rx)) + { + rt_dma_chan_release(pcm->rx); + } + if (!rt_is_err_or_null(pcm->tx)) + { + rt_dma_chan_release(pcm->tx); + } + if (pcm->hdmi_buffer) + { + rt_iounmap(pcm->hdmi_buffer); + } + + rt_free(pcm); +} + +static rt_err_t spacemit_pcm_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + rt_uint64_t address, size; + struct rt_device *dev = &pdev->parent; + struct spacemit_pcm *pcm = rt_calloc(1, sizeof(*pcm)); + + if (!pcm) + { + return -RT_ENOMEM; + } + + pcm->dev = dev; + pcm->np = dev->ofw_node; + pcm->is_hdmi = rt_ofw_node_is_compatible(dev->ofw_node, + "spacemit,spacemit-snd-dma-hdmi"); + + if (pcm->is_hdmi) + { + pcm->hdmi_buffer = rt_dm_dev_iomap(dev, 0); + if (!pcm->hdmi_buffer || + rt_dm_dev_get_address(dev, 0, &address, &size)) + { + err = -RT_EIO; + goto _fail; + } + + pcm->hdmi_dma = (rt_ubase_t)address; + pcm->hdmi_size = (rt_size_t)size; + rt_memset(pcm->hdmi_buffer, 0, pcm->hdmi_size); + rt_hw_wmb(); + } + + pcm->tx = rt_dma_chan_request(dev, "tx"); + if (rt_is_err_or_null(pcm->tx)) + { + err = pcm->tx ? rt_ptr_err(pcm->tx) : -RT_ENOSYS; + goto _fail; + } + + if (!pcm->is_hdmi) + { + pcm->rx = rt_dma_chan_request(dev, "rx"); + if (rt_is_err_or_null(pcm->rx)) + { + err = pcm->rx ? rt_ptr_err(pcm->rx) : -RT_ENOSYS; + goto _fail; + } + } + + rt_spin_lock(&pcm_nodes_lock); + rt_list_insert_before(&pcm_nodes, &pcm->list); + rt_spin_unlock(&pcm_nodes_lock); + + dev->user_data = pcm; + rt_dm_dev_bind_fwdata(dev, RT_NULL, pcm); + + LOG_D("%s: %s DMA path ready", rt_dm_dev_get_name(dev), + pcm->is_hdmi ? "HDMI" : "I2S"); + + return RT_EOK; + +_fail: + spacemit_pcm_free(pcm); + return err; +} + +static rt_err_t spacemit_pcm_remove(struct rt_platform_device *pdev) +{ + struct spacemit_pcm *pcm = pdev->parent.user_data; + + if (!pcm) + { + return RT_EOK; + } + + rt_spin_lock(&pcm_nodes_lock); + rt_list_remove(&pcm->list); + rt_spin_unlock(&pcm_nodes_lock); + + rt_dm_dev_unbind_fwdata(&pdev->parent, RT_NULL); + spacemit_pcm_free(pcm); + + return RT_EOK; +} + +static const struct rt_ofw_node_id spacemit_pcm_ofw_ids[] = +{ + { .compatible = "spacemit,spacemit-snd-dma0" }, + { .compatible = "spacemit,spacemit-snd-dma1" }, + { .compatible = "spacemit,spacemit-snd-dma-hdmi" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_pcm_driver = +{ + .name = "spacemit-audio-pcm", + .ids = spacemit_pcm_ofw_ids, + .probe = spacemit_pcm_probe, + .remove = spacemit_pcm_remove, +}; + +static int spacemit_pcm_register(void) +{ + rt_platform_driver_register(&spacemit_pcm_driver); + return 0; +} +INIT_DEVICE_EXPORT(spacemit_pcm_register); diff --git a/bsp/spacemit/dm/audio/spacemit-snd-sspa.c b/bsp/spacemit/dm/audio/spacemit-snd-sspa.c new file mode 100644 index 000000000000..f4a97ebb3199 --- /dev/null +++ b/bsp/spacemit/dm/audio/spacemit-snd-sspa.c @@ -0,0 +1,969 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#define DBG_TAG "audio.hdmi.spacemit" +#define DBG_LVL DBG_INFO +#include + +#include + +#include "spacemit-audio.h" +#include "spacemit-snd-sspa.h" + +#define K1_ADMA_HDMI_BYTES_PER_SECOND \ + (HDMI_SSPA_SAMPLE_RATE * 2U * sizeof(rt_uint32_t)) +#define K1_ADMA_RPMSG_LOCAL_ADDR 1024 +#define K1_ADMA_RPMSG_BOOT_TIMEOUT_MS 3000 +#define K1_ADMA_RPMSG_SEND_TIMEOUT_MS 1000 +#define K1_ADMA_RPMSG_STARTUP_MSG "startup" +#define K1_ADMA_RPMSG_STARTUP_OK_MSG "startup-ok" +struct spacemit_hdmi_audio +{ + struct rt_device *dev; + struct rt_ofw_node *np; + + void *regs; + void *clock_regs; + void *hdmi_regs; + rt_ubase_t phys; + + struct rt_clk *audio_clk; + struct rt_clk *hdmi_clk; + struct rt_reset_control *reset; + + int users; + rt_bool_t warned_unplugged; + rt_list_t list; +}; + +struct spacemit_adma +{ + struct rt_dma_controller parent; + struct rt_dma_chan channel; + struct rt_device *dev; + + void *regs; + void *control; + void *descriptors; + rt_ubase_t descriptors_dma; + + rt_ubase_t buffer_dma; + rt_size_t period_len; + rt_size_t period_count; + rt_size_t period_index; + rt_tick_t period_tick; + rt_uint32_t period_done_count; + rt_bool_t allocated; + rt_bool_t unpack_sample; + rt_bool_t running; + rt_bool_t rpmsg_started; +#ifdef RT_USING_RPMSG + struct rt_rpmsg_device *rpmsg_dev; + struct rt_rpmsg_endpoint *rpmsg_ept; + rt_uint32_t rpmsg_remote_addr; + struct rt_completion rpmsg_startup_done; + rt_uint32_t rpmsg_rx_count; + rt_bool_t rpmsg_startup_ready; +#endif +}; + +static rt_list_t hdmi_nodes = RT_LIST_OBJECT_INIT(hdmi_nodes); +static RT_DEFINE_SPINLOCK(hdmi_nodes_lock); +#ifdef RT_USING_RPMSG +static struct spacemit_adma *spacemit_adma_global; +static RT_DEFINE_SPINLOCK(spacemit_adma_global_lock); + +struct spacemit_rpmsg_char_ctrl +{ + struct rt_device parent; + struct rt_rpmsg_device *rdev; +}; +#endif + +struct spacemit_hdmi_audio *spacemit_hdmi_audio_find(struct rt_ofw_node *np) +{ + struct spacemit_hdmi_audio *hdmi; + + rt_spin_lock(&hdmi_nodes_lock); + rt_list_for_each_entry(hdmi, &hdmi_nodes, list) + { + if (hdmi->np == np) + { + rt_spin_unlock(&hdmi_nodes_lock); + return hdmi; + } + } + rt_spin_unlock(&hdmi_nodes_lock); + + return RT_NULL; +} + +rt_bool_t spacemit_hdmi_audio_connected(struct spacemit_hdmi_audio *hdmi) +{ + return hdmi && + (HWREG32((char *)hdmi->hdmi_regs + HDMI_PHY_STATUS) & HDMI_PHY_HPD); +} + +rt_err_t spacemit_hdmi_audio_start(struct spacemit_hdmi_audio *hdmi) +{ + rt_err_t err; + rt_ubase_t rate; + rt_uint32_t clock; + rt_uint32_t value; + + if (!hdmi) + { + return -RT_EINVAL; + } + + if (!hdmi->users) + { + if ((err = rt_clk_set_rate(hdmi->audio_clk, HDMI_SSPA_SAMPLE_RATE))) + { + LOG_E("failed to set HDMI audio clock: %s", rt_strerror(err)); + return err; + } + if ((err = rt_reset_control_deassert(hdmi->reset))) + { + LOG_E("failed to deassert HDMI audio reset: %s", rt_strerror(err)); + return err; + } + + rate = rt_clk_get_rate(hdmi->audio_clk); + clock = HWREG32((char *)hdmi->clock_regs + HDMI_SSPA_CLOCK_CONTROL); + if (rate != HDMI_SSPA_SAMPLE_RATE || + (clock & HDMI_SSPA_CLOCK_READY) != HDMI_SSPA_CLOCK_READY) + { + LOG_E("HDMI audio clock is not ready: rate=%lu ctrl=%08x", + (unsigned long)rate, clock); + return -RT_EIO; + } + + value = HWREG32((char *)hdmi->hdmi_regs + HDMI_AUDIO_ENABLE); + HWREG32((char *)hdmi->hdmi_regs + HDMI_AUDIO_ENABLE) = + value | HDMI_AUDIO_ENABLE_BIT; + rt_hw_wmb(); + value = HWREG32((char *)hdmi->hdmi_regs + HDMI_AUDIO_ENABLE); + if (!(value & HDMI_AUDIO_ENABLE_BIT)) + { + LOG_E("failed to enable HDMI audio path: ctrl=%08x", value); + return -RT_EIO; + } + + LOG_D("HDMI path enabled: rate=%lu clk=%08x audio=%08x HPD=%d", + (unsigned long)rate, clock, value, + spacemit_hdmi_audio_connected(hdmi)); + } + ++hdmi->users; + + if (!spacemit_hdmi_audio_connected(hdmi) && !hdmi->warned_unplugged) + { + hdmi->warned_unplugged = RT_TRUE; + LOG_W("HDMI is not connected; audio clock will keep running"); + } + + return RT_EOK; +} + +rt_err_t spacemit_hdmi_audio_stop(struct spacemit_hdmi_audio *hdmi) +{ + rt_uint32_t value; + + if (!hdmi) + { + return -RT_EINVAL; + } + + if (hdmi->users > 0 && !--hdmi->users) + { + value = HWREG32((char *)hdmi->hdmi_regs + HDMI_AUDIO_ENABLE); + HWREG32((char *)hdmi->hdmi_regs + HDMI_AUDIO_ENABLE) = + value & ~HDMI_AUDIO_ENABLE_BIT; + } + + return RT_EOK; +} + +rt_ubase_t spacemit_hdmi_audio_fifo_phys(struct spacemit_hdmi_audio *hdmi) +{ + return hdmi ? hdmi->phys + HDMI_SSPA_TX_DATA : 0; +} + +static void spacemit_adma_abort_hw(struct spacemit_adma *adma) +{ + rt_uint32_t control; + + control = HWREG32((char *)adma->regs + K1_ADMA_CONTROL); + HWREG32((char *)adma->regs + K1_ADMA_CONTROL) = control | K1_ADMA_ABORT; + rt_hw_us_delay(500); + control = HWREG32((char *)adma->regs + K1_ADMA_CONTROL); + HWREG32((char *)adma->regs + K1_ADMA_CONTROL) = + control & ~K1_ADMA_ENABLE; + HWREG32((char *)adma->regs + K1_ADMA_INT_ENABLE) = 0; + HWREG32((char *)adma->regs + K1_ADMA_INT_STATUS) = 0; + HWREG32(adma->control) = 0; +} + +static void spacemit_adma_stop_period(struct spacemit_adma *adma) +{ + adma->running = RT_FALSE; +} + +static rt_err_t spacemit_adma_build_ring(struct spacemit_adma *adma) +{ + rt_size_t index; + + if (adma->period_count * K1_ADMA_DESC_STRIDE > 0x400) + { + return -RT_EINVAL; + } + + for (index = 0; index < adma->period_count; ++index) + { + void *descriptor = (char *)adma->descriptors + + index * K1_ADMA_DESC_STRIDE; + rt_uint32_t next = (rt_uint32_t)(adma->descriptors_dma + + ((index + 1) % adma->period_count) * K1_ADMA_DESC_STRIDE); + + HWREG32((char *)descriptor + K1_ADMA_DESC_BYTE_COUNT) = + adma->period_len; + HWREG32((char *)descriptor + K1_ADMA_DESC_SOURCE_ADDR) = + (rt_uint32_t)(adma->buffer_dma + index * adma->period_len); + HWREG32((char *)descriptor + K1_ADMA_DESC_DEST_ADDR) = + (rt_uint32_t)adma->channel.conf.dst_addr; + HWREG32((char *)descriptor + K1_ADMA_DESC_NEXT) = next; + if (index < 4) + { + LOG_D("ADMA desc[%u]: BCR=%08x SAR=%08x DAR=%08x NDR=%08x", + (unsigned int)index, + HWREG32((char *)descriptor + K1_ADMA_DESC_BYTE_COUNT), + HWREG32((char *)descriptor + K1_ADMA_DESC_SOURCE_ADDR), + HWREG32((char *)descriptor + K1_ADMA_DESC_DEST_ADDR), + HWREG32((char *)descriptor + K1_ADMA_DESC_NEXT)); + } + } + rt_hw_wmb(); + + return RT_EOK; +} + +static void spacemit_adma_period_done(struct spacemit_adma *adma) +{ + if (!adma->running) + { + return; + } + + adma->period_index = (adma->period_index + 1) % adma->period_count; + adma->period_done_count++; + if (adma->period_done_count <= 4 || + !(adma->period_done_count % 100)) + { + LOG_D("ADMA period done #%u", adma->period_done_count); + } + rt_dma_chan_done(&adma->channel, adma->period_len); +} + +#ifdef RT_USING_RPMSG +static struct rt_rpmsg_device *spacemit_adma_get_rpmsg_device(void) +{ + char name[16]; + rt_device_t dev = RT_NULL; + + for (int i = 0; i < 4; ++i) + { + struct spacemit_rpmsg_char_ctrl *ctrl; + + rt_snprintf(name, sizeof(name), "rpmsg_char%d", i); + dev = rt_device_find(name); + if (dev) + { + ctrl = rt_container_of(dev, struct spacemit_rpmsg_char_ctrl, + parent); + if (ctrl->rdev) + { + LOG_D("ADMA RPMsg transport found via %s", name); + return ctrl->rdev; + } + } + } + + LOG_E("ADMA RPMsg control device rpmsg_charN not found"); + return RT_NULL; +} + +static rt_bool_t spacemit_adma_get_remote_addr(struct rt_rpmsg_device *rdev, + rt_uint32_t *addr) +{ + rt_ubase_t level; + struct rt_rpmsg_endpoint *ept; + + level = rt_spin_lock_irqsave(&rdev->lock); + rt_list_for_each_entry(ept, &rdev->ept_nodes, list) + { + if (ept->info.src == RT_RPMSG_ADDR_ANY && + ept->info.dst != RT_RPMSG_ADDR_ANY && + !rt_strncmp(ept->info.name, "adma-service", RT_RPMSG_NAME_SIZE)) + { + *addr = ept->info.dst; + rt_spin_unlock_irqrestore(&rdev->lock, level); + return RT_TRUE; + } + } + rt_spin_unlock_irqrestore(&rdev->lock, level); + + return RT_FALSE; +} + +static rt_err_t spacemit_adma_rpmsg_rx(struct rt_rpmsg_device *rdev, + rt_uint32_t src, void *data, rt_size_t len) +{ + rt_ubase_t level; + struct spacemit_adma *adma; + rt_bool_t startup_ok = RT_FALSE; + rt_bool_t period_done = RT_FALSE; + + RT_UNUSED(rdev); + + level = rt_spin_lock_irqsave(&spacemit_adma_global_lock); + adma = spacemit_adma_global; + rt_spin_unlock_irqrestore(&spacemit_adma_global_lock, level); + + if (adma && data && len) + { + adma->rpmsg_rx_count++; + startup_ok = len >= sizeof(K1_ADMA_RPMSG_STARTUP_OK_MSG) - 1 && + !rt_memcmp(data, K1_ADMA_RPMSG_STARTUP_OK_MSG, + sizeof(K1_ADMA_RPMSG_STARTUP_OK_MSG) - 1); + period_done = *(const char *)data == '#'; + + if (adma->rpmsg_rx_count <= 8 || + !(adma->rpmsg_rx_count % 100)) + { + LOG_D("ADMA RPMsg rx #%u: src=%u len=%u type=%s running=%d", + adma->rpmsg_rx_count, src, (unsigned int)len, + startup_ok ? "startup-ok" : + (period_done ? "period" : "unknown"), adma->running); + } + } + + if (adma && startup_ok) + { + adma->rpmsg_startup_ready = RT_TRUE; + rt_completion_done(&adma->rpmsg_startup_done); + } + else if (adma && period_done && adma->running) + { + spacemit_adma_period_done(adma); + } + + return RT_EOK; +} + +static rt_err_t spacemit_adma_create_rpmsg_endpoint(struct spacemit_adma *adma) +{ + struct rt_rpmsg_endpoint_info info; + + if (adma->rpmsg_ept) + { + return RT_EOK; + } + + if (!adma->rpmsg_dev) + { + adma->rpmsg_dev = spacemit_adma_get_rpmsg_device(); + if (!adma->rpmsg_dev) + { + return -RT_EBUSY; + } + } + + rt_memset(&info, 0, sizeof(info)); + rt_strncpy(info.name, "adma-service", RT_RPMSG_NAME_SIZE); + info.src = K1_ADMA_RPMSG_LOCAL_ADDR; + info.dst = RT_RPMSG_NS_ADDR; + + adma->rpmsg_ept = rt_rpmsg_create_endpoint(adma->rpmsg_dev, + &info, spacemit_adma_rpmsg_rx); + if (rt_is_err(adma->rpmsg_ept)) + { + rt_err_t err = rt_ptr_err(adma->rpmsg_ept); + + adma->rpmsg_ept = RT_NULL; + LOG_E("ADMA RPMsg endpoint create failed: %s", rt_strerror(err)); + return err; + } + + LOG_D("ADMA RPMsg endpoint created: src=%u", + K1_ADMA_RPMSG_LOCAL_ADDR); + + return RT_EOK; +} + +static rt_err_t spacemit_adma_ensure_rpmsg(struct spacemit_adma *adma) +{ + rt_err_t err; + rt_tick_t deadline; + rt_uint32_t remote_addr = RT_RPMSG_ADDR_ANY; + +#ifdef RT_SOC_SPACEMIT_K1X_RPROC + err = spacemit_k1x_rproc_boot("esos.elf"); + if (err) + { + LOG_E("RCPU firmware is not ready: %s", rt_strerror(err)); + return err; + } +#else + LOG_E("ADMA requires K1X RCPU remoteproc"); + return -RT_EBUSY; +#endif + + err = spacemit_adma_create_rpmsg_endpoint(adma); + if (err) + { + LOG_E("ADMA RPMsg endpoint is not ready: %s", rt_strerror(err)); + return err; + } + + deadline = rt_tick_get() + + rt_tick_from_millisecond(K1_ADMA_RPMSG_BOOT_TIMEOUT_MS); + while (!spacemit_adma_get_remote_addr(adma->rpmsg_dev, &remote_addr)) + { + if ((rt_int32_t)(rt_tick_get() - deadline) >= 0) + { + LOG_E("RCPU adma-service is not ready"); + spacemit_k1x_rproc_dump_status(); + return -RT_EBUSY; + } + rt_thread_mdelay(10); + } + + if (adma->rpmsg_remote_addr != remote_addr) + { + LOG_D("ADMA RPMsg remote service: dst=%u", remote_addr); + adma->rpmsg_remote_addr = remote_addr; + adma->rpmsg_started = RT_FALSE; + adma->rpmsg_startup_ready = RT_FALSE; + } + + if (!adma->rpmsg_started) + { + rt_completion_init(&adma->rpmsg_startup_done); + adma->rpmsg_startup_ready = RT_FALSE; + err = rt_rpmsg_sendto_wait(adma->rpmsg_ept, remote_addr, + K1_ADMA_RPMSG_STARTUP_MSG, + sizeof(K1_ADMA_RPMSG_STARTUP_MSG) - 1, + rt_tick_from_millisecond(K1_ADMA_RPMSG_SEND_TIMEOUT_MS)); + if (err) + { + LOG_E("ADMA RPMsg startup failed: %s", rt_strerror(err)); + return err; + } + LOG_D("ADMA RPMsg startup sent"); + + err = rt_completion_wait(&adma->rpmsg_startup_done, + rt_tick_from_millisecond(K1_ADMA_RPMSG_SEND_TIMEOUT_MS)); + if (err || !adma->rpmsg_startup_ready) + { + LOG_E("ADMA RPMsg startup reply timeout"); + spacemit_k1x_rproc_dump_status(); + return -RT_ETIMEOUT; + } + + adma->rpmsg_started = RT_TRUE; + LOG_D("ADMA RPMsg startup acknowledged"); + } + + return RT_EOK; +} +#else +static rt_err_t spacemit_adma_ensure_rpmsg(struct spacemit_adma *adma) +{ + RT_UNUSED(adma); + + LOG_E("ADMA requires RT_USING_RPMSG"); + return -RT_EBUSY; +} +#endif + +static struct rt_dma_chan *spacemit_adma_request(struct rt_dma_controller *controller, + struct rt_device *slave, void *fw_data) +{ + struct spacemit_adma *adma = rt_container_of(controller, + struct spacemit_adma, parent); + + RT_UNUSED(slave); + RT_UNUSED(fw_data); + + if (adma->allocated) + { + return rt_err_ptr(-RT_EBUSY); + } + + adma->allocated = RT_TRUE; + return &adma->channel; +} + +static rt_err_t spacemit_adma_release(struct rt_dma_chan *channel) +{ + struct spacemit_adma *adma = rt_container_of(channel, + struct spacemit_adma, channel); + + spacemit_adma_stop_period(adma); + adma->allocated = RT_FALSE; + + return RT_EOK; +} + +static rt_err_t spacemit_adma_config(struct rt_dma_chan *channel, + struct rt_dma_slave_config *config) +{ + LOG_D("ADMA config: dir=%d src=%08lx dst=%08lx sw=%u dw=%u burst=%u/%u", + config->direction, + (unsigned long)config->src_addr, + (unsigned long)config->dst_addr, + (unsigned int)config->src_addr_width, + (unsigned int)config->dst_addr_width, + (unsigned int)config->src_maxburst, + (unsigned int)config->dst_maxburst); + if (config->direction != RT_DMA_MEM_TO_DEV || + config->dst_addr_width != RT_DMA_SLAVE_BUSWIDTH_4_BYTES) + { + LOG_E("ADMA config rejected"); + return -RT_EINVAL; + } + + RT_UNUSED(channel); + return RT_EOK; +} + +static rt_err_t spacemit_adma_prep_cyclic(struct rt_dma_chan *channel, + rt_ubase_t buffer, rt_size_t length, rt_size_t period, + enum rt_dma_transfer_direction direction) +{ + rt_size_t count; + struct spacemit_adma *adma = rt_container_of(channel, + struct spacemit_adma, channel); + + LOG_D("ADMA prep cyclic: buf=%08lx len=%u period=%u dir=%d dst=%08lx", + (unsigned long)buffer, (unsigned int)length, + (unsigned int)period, direction, + (unsigned long)channel->conf.dst_addr); + if (direction != RT_DMA_MEM_TO_DEV || !period || length % period || + buffer > 0xffffffffUL || channel->conf.dst_addr > 0xffffffffUL) + { + LOG_E("ADMA prep rejected"); + return -RT_EINVAL; + } + + count = length / period; + if (!count) + { + return -RT_EINVAL; + } + + adma->buffer_dma = buffer; + adma->period_len = period; + adma->period_count = count; + adma->period_index = 0; + adma->period_tick = (rt_tick_t)(((rt_uint64_t)period * + RT_TICK_PER_SECOND + K1_ADMA_HDMI_BYTES_PER_SECOND - 1U) / + K1_ADMA_HDMI_BYTES_PER_SECOND); + if (!adma->period_tick) + { + adma->period_tick = 1; + } + LOG_D("ADMA prep done: count=%u tick=%u", + (unsigned int)adma->period_count, + (unsigned int)adma->period_tick); + + return RT_EOK; +} + +static rt_err_t spacemit_adma_start(struct rt_dma_chan *channel) +{ + rt_err_t err; + rt_uint32_t control; + struct spacemit_adma *adma = rt_container_of(channel, + struct spacemit_adma, channel); + + LOG_D("ADMA start begin"); + if ((err = spacemit_adma_ensure_rpmsg(adma))) + { + LOG_E("ADMA remote service failed: %s", rt_strerror(err)); + return err; + } + + control = HWREG32((char *)adma->regs + K1_ADMA_CONTROL); + LOG_D("ADMA start hw state: BCR=%08x SAR=%08x DAR=%08x NDR=%08x " + "DCR=%08x CUR=%08x IER=%08x ISR=%08x CTRL=%08x", + HWREG32((char *)adma->regs + K1_ADMA_BYTE_COUNT), + HWREG32((char *)adma->regs + K1_ADMA_SOURCE_ADDR), + HWREG32((char *)adma->regs + K1_ADMA_DEST_ADDR), + HWREG32((char *)adma->regs + K1_ADMA_NEXT_DESC), + control, + HWREG32((char *)adma->regs + K1_ADMA_CURRENT_DESC), + HWREG32((char *)adma->regs + K1_ADMA_INT_ENABLE), + HWREG32((char *)adma->regs + K1_ADMA_INT_STATUS), + HWREG32(adma->control)); + if (control & K1_ADMA_ENABLE) + { + HWREG32((char *)adma->regs + K1_ADMA_CONTROL) = + control | K1_ADMA_ABORT; + rt_hw_us_delay(500); + HWREG32((char *)adma->regs + K1_ADMA_CONTROL) = + control & ~K1_ADMA_ENABLE; + } + + HWREG32((char *)adma->regs + K1_ADMA_INT_ENABLE) = 0; + HWREG32((char *)adma->regs + K1_ADMA_INT_STATUS) = 0; + control = K1_ADMA_SAMPLE_BITS(5) | K1_ADMA_ABORT | + K1_ADMA_DST_HOLD | K1_ADMA_SRC_INCREMENT; + if (adma->unpack_sample) + { + control |= K1_ADMA_UNPACK; + } + adma->period_index = 0; + adma->period_done_count = 0; + LOG_D("ADMA build ring begin"); + if ((err = spacemit_adma_build_ring(adma))) + { + LOG_E("ADMA build ring failed: %s", rt_strerror(err)); + return err; + } + LOG_D("ADMA build ring done"); + + HWREG32((char *)adma->regs + K1_ADMA_NEXT_DESC) = + (rt_uint32_t)adma->descriptors_dma; + HWREG32((char *)adma->regs + K1_ADMA_CONTROL) = control; + HWREG32(adma->control) = adma->unpack_sample ? 0 : K1_ADMA_HDMI_ENABLE; + HWREG32((char *)adma->regs + K1_ADMA_DEST_ADDR) = + (rt_uint32_t)adma->channel.conf.dst_addr; + HWREG32((char *)adma->regs + K1_ADMA_INT_ENABLE) = 1; + rt_hw_wmb(); + + /* ABORT is a command bit and clears itself. Reads DCR back before + * enabling the channel so ABORT is not asserted together with CH_EN. */ + adma->running = RT_TRUE; + control = HWREG32((char *)adma->regs + K1_ADMA_CONTROL); + HWREG32((char *)adma->regs + K1_ADMA_CONTROL) = control | + K1_ADMA_FETCH_NEXT_DESC | K1_ADMA_ENABLE; + rt_hw_wmb(); + + LOG_D("ADMA started: DCR=%08x CUR=%08x NDR=%08x CTRL=%08x", + HWREG32((char *)adma->regs + K1_ADMA_CONTROL), + HWREG32((char *)adma->regs + K1_ADMA_CURRENT_DESC), + HWREG32((char *)adma->regs + K1_ADMA_NEXT_DESC), + HWREG32(adma->control)); + return RT_EOK; +} + +static rt_err_t spacemit_adma_stop(struct rt_dma_chan *channel) +{ + struct spacemit_adma *adma = rt_container_of(channel, + struct spacemit_adma, channel); + + spacemit_adma_stop_period(adma); + + spacemit_adma_abort_hw(adma); + + return RT_EOK; +} + +static const struct rt_dma_controller_ops spacemit_adma_ops = +{ + .request_chan = spacemit_adma_request, + .release_chan = spacemit_adma_release, + .start = spacemit_adma_start, + .stop = spacemit_adma_stop, + .config = spacemit_adma_config, + .prep_cyclic = spacemit_adma_prep_cyclic, +}; + +static rt_err_t spacemit_adma_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + rt_uint64_t address; + struct rt_device *dev = &pdev->parent; + struct spacemit_adma *adma = rt_calloc(1, sizeof(*adma)); + + if (!adma) + { + return -RT_ENOMEM; + } + + adma->dev = dev; + adma->regs = rt_dm_dev_iomap(dev, 0); + adma->control = rt_dm_dev_iomap(dev, 1); + adma->descriptors = rt_dm_dev_iomap(dev, 2); + if (!adma->regs || !adma->control || !adma->descriptors || + rt_dm_dev_get_address(dev, 2, &address, RT_NULL) || + address > 0xffffffffULL) + { + err = -RT_EIO; + goto _fail; + } + adma->descriptors_dma = (rt_ubase_t)address; + adma->unpack_sample = !rt_dm_dev_prop_read_bool(dev, "hdmi-sample"); +#ifdef RT_USING_RPMSG + adma->rpmsg_remote_addr = RT_RPMSG_ADDR_ANY; + rt_completion_init(&adma->rpmsg_startup_done); +#endif + + adma->parent.dev = dev; + adma->parent.ops = &spacemit_adma_ops; + rt_dma_controller_add_direction(&adma->parent, RT_DMA_MEM_TO_DEV); + rt_dma_controller_set_addr_mask(&adma->parent, RT_DMA_ADDR_MASK(32)); + if ((err = rt_dma_controller_register(&adma->parent))) + { + goto _fail; + } + + dev->user_data = adma; +#ifdef RT_USING_RPMSG + rt_spin_lock(&spacemit_adma_global_lock); + spacemit_adma_global = adma; + rt_spin_unlock(&spacemit_adma_global_lock); +#endif + LOG_D("K1 HDMI ADMA ready in cyclic descriptor mode, hdmi-sample=%d", + !adma->unpack_sample); + + return RT_EOK; + +_fail: + if (adma->regs) + { + rt_iounmap(adma->regs); + } + if (adma->control) + { + rt_iounmap(adma->control); + } + if (adma->descriptors) + { + rt_iounmap(adma->descriptors); + } + rt_free(adma); + return err; +} + +static rt_err_t spacemit_adma_remove(struct rt_platform_device *pdev) +{ + struct spacemit_adma *adma = pdev->parent.user_data; + + if (!adma) + { + return RT_EOK; + } + + if (rt_dma_controller_unregister(&adma->parent)) + { + return -RT_EBUSY; + } + + spacemit_adma_stop_period(adma); +#ifdef RT_USING_RPMSG + rt_spin_lock(&spacemit_adma_global_lock); + if (spacemit_adma_global == adma) + { + spacemit_adma_global = RT_NULL; + } + rt_spin_unlock(&spacemit_adma_global_lock); + if (adma->rpmsg_dev && adma->rpmsg_ept) + { + rt_rpmsg_destroy_endpoint(adma->rpmsg_dev, adma->rpmsg_ept); + } +#endif + rt_iounmap(adma->regs); + rt_iounmap(adma->control); + rt_iounmap(adma->descriptors); + rt_free(adma); + + return RT_EOK; +} + +static const struct rt_ofw_node_id spacemit_adma_ofw_ids[] = +{ + { .compatible = "spacemit,k1x-adma" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_adma_driver = +{ + .name = "spacemit-hdmi-adma", + .ids = spacemit_adma_ofw_ids, + .probe = spacemit_adma_probe, + .remove = spacemit_adma_remove, +}; + +static int spacemit_adma_register(void) +{ + rt_platform_driver_register(&spacemit_adma_driver); + return 0; +} +INIT_SUBSYS_EXPORT(spacemit_adma_register); + +static void spacemit_hdmi_audio_free(struct spacemit_hdmi_audio *hdmi) +{ + if (!hdmi) + { + return; + } + + if (!rt_is_err_or_null(hdmi->reset)) + { + rt_reset_control_assert(hdmi->reset); + rt_reset_control_put(hdmi->reset); + } + if (!rt_is_err_or_null(hdmi->audio_clk)) + { + rt_clk_disable_unprepare(hdmi->audio_clk); + rt_clk_put(hdmi->audio_clk); + } + if (!rt_is_err_or_null(hdmi->hdmi_clk)) + { + rt_clk_disable_unprepare(hdmi->hdmi_clk); + rt_clk_put(hdmi->hdmi_clk); + } + if (hdmi->regs) + { + rt_iounmap(hdmi->regs); + } + if (hdmi->clock_regs) + { + rt_iounmap(hdmi->clock_regs); + } + if (hdmi->hdmi_regs) + { + rt_iounmap(hdmi->hdmi_regs); + } + rt_free(hdmi); +} + +static rt_err_t spacemit_hdmi_audio_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + rt_uint64_t address; + struct rt_device *dev = &pdev->parent; + struct spacemit_hdmi_audio *hdmi = rt_calloc(1, sizeof(*hdmi)); + + if (!hdmi) + { + return -RT_ENOMEM; + } + + hdmi->dev = dev; + hdmi->np = dev->ofw_node; + hdmi->regs = rt_dm_dev_iomap(dev, 0); + hdmi->clock_regs = rt_dm_dev_iomap(dev, 1); + hdmi->hdmi_regs = rt_ioremap((void *)HDMI_PHY_BASE, HDMI_PHY_SIZE); + if (!hdmi->regs || !hdmi->clock_regs || !hdmi->hdmi_regs || + rt_dm_dev_get_address(dev, 0, &address, RT_NULL)) + { + err = -RT_EIO; + goto _fail; + } + hdmi->phys = (rt_ubase_t)address; + + hdmi->audio_clk = rt_clk_get_by_index(dev, 0); + if (rt_is_err(hdmi->audio_clk)) + { + err = rt_ptr_err(hdmi->audio_clk); + goto _fail; + } + if ((err = rt_clk_set_rate(hdmi->audio_clk, HDMI_SSPA_SAMPLE_RATE))) + { + goto _fail; + } + if ((err = rt_clk_prepare_enable(hdmi->audio_clk))) + { + goto _fail; + } + + hdmi->hdmi_clk = rt_clk_get_by_index(dev, 1); + if (!rt_is_err(hdmi->hdmi_clk)) + { + if ((err = rt_clk_prepare_enable(hdmi->hdmi_clk))) + { + goto _fail; + } + } + + hdmi->reset = rt_reset_control_get_by_index(dev, 0); + if (rt_is_err(hdmi->reset)) + { + err = rt_ptr_err(hdmi->reset); + goto _fail; + } + if ((err = rt_reset_control_deassert(hdmi->reset))) + { + goto _fail; + } + + LOG_D("%s: clock=%lu Hz ctrl=%08x", rt_dm_dev_get_name(dev), + (unsigned long)rt_clk_get_rate(hdmi->audio_clk), + HWREG32((char *)hdmi->clock_regs + HDMI_SSPA_CLOCK_CONTROL)); + + rt_spin_lock(&hdmi_nodes_lock); + rt_list_insert_before(&hdmi_nodes, &hdmi->list); + rt_spin_unlock(&hdmi_nodes_lock); + + dev->user_data = hdmi; + rt_dm_dev_bind_fwdata(dev, RT_NULL, hdmi); + + LOG_D("%s: HDMI SSPA ready, HPD=%d", rt_dm_dev_get_name(dev), + spacemit_hdmi_audio_connected(hdmi)); + + return RT_EOK; + +_fail: + spacemit_hdmi_audio_free(hdmi); + return err; +} + +static rt_err_t spacemit_hdmi_audio_remove(struct rt_platform_device *pdev) +{ + struct spacemit_hdmi_audio *hdmi = pdev->parent.user_data; + + if (!hdmi) + { + return RT_EOK; + } + + rt_spin_lock(&hdmi_nodes_lock); + rt_list_remove(&hdmi->list); + rt_spin_unlock(&hdmi_nodes_lock); + + rt_dm_dev_unbind_fwdata(&pdev->parent, RT_NULL); + spacemit_hdmi_audio_free(hdmi); + + return RT_EOK; +} + +static const struct rt_ofw_node_id spacemit_hdmi_audio_ofw_ids[] = +{ + { .compatible = "spacemit,spacemit-snd-sspa" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_hdmi_audio_driver = +{ + .name = "spacemit-hdmi-audio", + .ids = spacemit_hdmi_audio_ofw_ids, + .probe = spacemit_hdmi_audio_probe, + .remove = spacemit_hdmi_audio_remove, +}; + +static int spacemit_hdmi_audio_register(void) +{ + rt_platform_driver_register(&spacemit_hdmi_audio_driver); + return 0; +} +INIT_DEVICE_EXPORT(spacemit_hdmi_audio_register); diff --git a/bsp/spacemit/dm/audio/spacemit-snd-sspa.h b/bsp/spacemit/dm/audio/spacemit-snd-sspa.h new file mode 100644 index 000000000000..b86321e539da --- /dev/null +++ b/bsp/spacemit/dm/audio/spacemit-snd-sspa.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __SPACEMIT_SND_SSPA_H__ +#define __SPACEMIT_SND_SSPA_H__ + +#include + +#define HDMI_SSPA_TX_DATA 0x80 + +#define HDMI_PHY_BASE 0xc0400500UL +#define HDMI_PHY_SIZE 0x200 +#define HDMI_PHY_STATUS 0x0c +#define HDMI_PHY_HPD RT_BIT(12) +#define HDMI_AUDIO_ENABLE 0x30 +#define HDMI_AUDIO_ENABLE_BIT RT_BIT(0) + +#define HDMI_SSPA_CLOCK_CONTROL 0x44 +#define HDMI_SSPA_CLOCK_READY 0x7 +#define HDMI_SSPA_SAMPLE_RATE 48000 + +#define K1_ADMA_BYTE_COUNT 0x00 +#define K1_ADMA_SOURCE_ADDR 0x10 +#define K1_ADMA_DEST_ADDR 0x20 +#define K1_ADMA_NEXT_DESC 0x30 +#define K1_ADMA_CONTROL 0x40 +#define K1_ADMA_CURRENT_DESC 0x70 +#define K1_ADMA_INT_ENABLE 0x80 +#define K1_ADMA_INT_STATUS 0xa0 + +#define K1_ADMA_SAMPLE_BITS(v) (((v) & 0x7U) << 22) +#define K1_ADMA_ABORT RT_BIT(20) +#define K1_ADMA_UNPACK RT_BIT(16) +#define K1_ADMA_ACTIVE RT_BIT(14) +#define K1_ADMA_FETCH_NEXT_DESC RT_BIT(13) +#define K1_ADMA_ENABLE RT_BIT(12) +#define K1_ADMA_DST_HOLD (0x2U << 4) +#define K1_ADMA_SRC_INCREMENT (0x0U << 2) + +#define K1_ADMA_HDMI_ENABLE RT_BIT(0) + +#define K1_ADMA_DESC_BYTE_COUNT 0x00 +#define K1_ADMA_DESC_SOURCE_ADDR 0x04 +#define K1_ADMA_DESC_DEST_ADDR 0x08 +#define K1_ADMA_DESC_NEXT 0x0c +#define K1_ADMA_DESC_STRIDE 0x100 + +#endif /* __SPACEMIT_SND_SSPA_H__ */ diff --git a/bsp/spacemit/dm/clk/Kconfig b/bsp/spacemit/dm/clk/Kconfig new file mode 100644 index 000000000000..abc9ab79a3c6 --- /dev/null +++ b/bsp/spacemit/dm/clk/Kconfig @@ -0,0 +1,9 @@ +menuconfig RT_CLK_SPACEMIT + bool "Spacemit clock controller common" + depends on RT_USING_OFW + default y + +config RT_CLK_SPACEMIT_K1X + bool "Spacemit k1x clock controller support" + depends on RT_CLK_SPACEMIT + default n diff --git a/bsp/spacemit/dm/clk/SConscript b/bsp/spacemit/dm/clk/SConscript new file mode 100644 index 000000000000..3051d69dfb64 --- /dev/null +++ b/bsp/spacemit/dm/clk/SConscript @@ -0,0 +1,15 @@ +from building import * + +cwd = GetCurrentDir() +src = [] +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_CLK_SPACEMIT']): + src += ['ccu_ddn.c', 'ccu_ddr.c', 'ccu_dpll.c', 'ccu_mix.c', 'ccu_pll.c'] + + if GetDepend(['RT_CLK_SPACEMIT_K1X']): + src += ['ccu-spacemit-k1x.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/clk/ccu-spacemit-k1x.c b/bsp/spacemit/dm/clk/ccu-spacemit-k1x.c new file mode 100644 index 000000000000..69cee1d44878 --- /dev/null +++ b/bsp/spacemit/dm/clk/ccu-spacemit-k1x.c @@ -0,0 +1,1244 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include + +#include "ccu_ddn.h" +#include "ccu_ddr.h" +#include "ccu_mix.h" +#include "ccu_dpll.h" +#include "ccu_pll.h" + +#include +#include + +struct k1x_clk +{ + struct rt_clk_node parent; + + union + { + struct + { + void *mpmu_base; + void *apmu_base; + void *apbc_base; + void *apbs_base; + void *ciu_base; + void *dciu_base; + void *ddrc_base; + void *apbc2_base; + void *rcpu_base; + void *rcpu2_base; + void *audpmu_base; + void *audio_ctrl_base; + }; + void *mmio[CRU_BASE_TYPE_MAX]; + }; +}; + +static const struct ccu_pll_rate_tbl pll2_rate_tbl[] = +{ + PLL_RATE(3000000000UL, 0x66, 0xdd, 0x50, 0x00, 0x3f, 0xe00000), + PLL_RATE(3200000000UL, 0x67, 0xdd, 0x50, 0x00, 0x43, 0xeaaaab), + PLL_RATE(2457600000UL, 0x64, 0xdd, 0x50, 0x00, 0x33, 0x0ccccd), + PLL_RATE(2800000000UL, 0x66, 0xdd, 0x50, 0x00, 0x3a, 0x155555), +}; + +static const struct ccu_pll_rate_tbl pll3_rate_tbl[] = +{ + PLL_RATE(1600000000UL, 0x61, 0xcd, 0x50, 0x00, 0x43, 0xeaaaab), + PLL_RATE(1800000000UL, 0x61, 0xcd, 0x50, 0x00, 0x4b, 0x000000), + PLL_RATE(2000000000UL, 0x62, 0xdd, 0x50, 0x00, 0x2a, 0xeaaaab), + PLL_RATE(3000000000UL, 0x66, 0xdd, 0x50, 0x00, 0x3f, 0xe00000), + PLL_RATE(3200000000UL, 0x67, 0xdd, 0x50, 0x00, 0x43, 0xeaaaab), + PLL_RATE(2457600000UL, 0x64, 0xdd, 0x50, 0x00, 0x33, 0x0ccccd), +}; + +static SPACEMIT_CCU_PLL(pll2, "pll2", &pll2_rate_tbl, RT_ARRAY_SIZE(pll2_rate_tbl), + CRU_BASE_TYPE_APBS, APB_SPARE7_REG, APB_SPARE8_REG, APB_SPARE9_REG, + MPMU_POSR, POSR_PLL2_LOCK, 1, RT_CLK_F_IGNORE_UNUSED); + +static SPACEMIT_CCU_PLL(pll3, "pll3", &pll3_rate_tbl, RT_ARRAY_SIZE(pll3_rate_tbl), + CRU_BASE_TYPE_APBS, APB_SPARE10_REG, APB_SPARE11_REG, APB_SPARE12_REG, + MPMU_POSR, POSR_PLL3_LOCK, 1, RT_CLK_F_IGNORE_UNUSED); + +/* PLL1 */ +static SPACEMIT_CCU_GATE_FACTOR(pll1_d2, "pll1_d2", "pll1_2457p6_vco", + CRU_BASE_TYPE_APBS, APB_SPARE2_REG, RT_BIT(1), RT_BIT(1), 0x0, 2, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll1_d3, "pll1_d3", "pll1_2457p6_vco", + CRU_BASE_TYPE_APBS, APB_SPARE2_REG, RT_BIT(2), RT_BIT(2), 0x0, 3, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll1_d4, "pll1_d4", "pll1_2457p6_vco", + CRU_BASE_TYPE_APBS, APB_SPARE2_REG, RT_BIT(3), RT_BIT(3), 0x0, 4, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll1_d5, "pll1_d5", "pll1_2457p6_vco", + CRU_BASE_TYPE_APBS, APB_SPARE2_REG, RT_BIT(4), RT_BIT(4), 0x0, 5, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll1_d6, "pll1_d6", "pll1_2457p6_vco", + CRU_BASE_TYPE_APBS, APB_SPARE2_REG, RT_BIT(5), RT_BIT(5), 0x0, 6, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll1_d7, "pll1_d7", "pll1_2457p6_vco", + CRU_BASE_TYPE_APBS, APB_SPARE2_REG, RT_BIT(6), RT_BIT(6), 0x0, 7, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll1_d8, "pll1_d8", "pll1_2457p6_vco", + CRU_BASE_TYPE_APBS, APB_SPARE2_REG, RT_BIT(7), RT_BIT(7), 0x0, 8, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll1_d11_223p4, "pll1_d11_223p4", "pll1_2457p6_vco", + CRU_BASE_TYPE_APBS, APB_SPARE2_REG, RT_BIT(15), RT_BIT(15), 0x0, 11, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll1_d13_189, "pll1_d13_189", "pll1_2457p6_vco", + CRU_BASE_TYPE_APBS, APB_SPARE2_REG, RT_BIT(16), RT_BIT(16), 0x0, 13, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll1_d23_106p8, "pll1_d23_106p8", "pll1_2457p6_vco", + CRU_BASE_TYPE_APBS, APB_SPARE2_REG, RT_BIT(20), RT_BIT(20), 0x0, 23, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll1_d64_38p4, "pll1_d64_38p4", "pll1_2457p6_vco", + CRU_BASE_TYPE_APBS, APB_SPARE2_REG, RT_BIT(0), RT_BIT(0), 0x0, 64, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll1_aud_245p7, "pll1_aud_245p7", "pll1_2457p6_vco", + CRU_BASE_TYPE_APBS, APB_SPARE2_REG, RT_BIT(10), RT_BIT(10), 0x0, 10, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll1_aud_24p5, "pll1_aud_24p5", "pll1_2457p6_vco", + CRU_BASE_TYPE_APBS, APB_SPARE2_REG, RT_BIT(11), RT_BIT(11), 0x0, 100, 1, RT_CLK_F_IGNORE_UNUSED); + +/* PLL2 */ +static SPACEMIT_CCU_GATE_FACTOR(pll2_d1, "pll2_d1", "pll2", + CRU_BASE_TYPE_APBS, APB_SPARE8_REG, RT_BIT(0), RT_BIT(0), 0x0, 1, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll2_d2, "pll2_d2", "pll2", + CRU_BASE_TYPE_APBS, APB_SPARE8_REG, RT_BIT(1), RT_BIT(1), 0x0, 2, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll2_d3, "pll2_d3", "pll2", + CRU_BASE_TYPE_APBS, APB_SPARE8_REG, RT_BIT(2), RT_BIT(2), 0x0, 3, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll2_d4, "pll2_d4", "pll2", + CRU_BASE_TYPE_APBS, APB_SPARE8_REG, RT_BIT(3), RT_BIT(3), 0x0, 4, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll2_d5, "pll2_d5", "pll2", + CRU_BASE_TYPE_APBS, APB_SPARE8_REG, RT_BIT(4), RT_BIT(4), 0x0, 5, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll2_d6, "pll2_d6", "pll2", + CRU_BASE_TYPE_APBS, APB_SPARE8_REG, RT_BIT(5), RT_BIT(5), 0x0, 6, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll2_d7, "pll2_d7", "pll2", + CRU_BASE_TYPE_APBS, APB_SPARE8_REG, RT_BIT(6), RT_BIT(6), 0x0, 7, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll2_d8, "pll2_d8", "pll2", + CRU_BASE_TYPE_APBS, APB_SPARE8_REG, RT_BIT(7), RT_BIT(7), 0x0, 8, 1, RT_CLK_F_IGNORE_UNUSED); + +/* PLL3 */ +static SPACEMIT_CCU_GATE_FACTOR(pll3_d1, "pll3_d1", "pll3", + CRU_BASE_TYPE_APBS, APB_SPARE11_REG, RT_BIT(0), RT_BIT(0), 0x0, 1, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll3_d2, "pll3_d2", "pll3", + CRU_BASE_TYPE_APBS, APB_SPARE11_REG, RT_BIT(1), RT_BIT(1), 0x0, 2, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll3_d3, "pll3_d3", "pll3", + CRU_BASE_TYPE_APBS, APB_SPARE11_REG, RT_BIT(2), RT_BIT(2), 0x0, 3, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll3_d4, "pll3_d4", "pll3", + CRU_BASE_TYPE_APBS, APB_SPARE11_REG, RT_BIT(3), RT_BIT(3), 0x0, 4, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll3_d5, "pll3_d5", "pll3", + CRU_BASE_TYPE_APBS, APB_SPARE11_REG, RT_BIT(4), RT_BIT(4), 0x0, 5, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll3_d6, "pll3_d6", "pll3", + CRU_BASE_TYPE_APBS, APB_SPARE11_REG, RT_BIT(5), RT_BIT(5), 0x0, 6, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll3_d7, "pll3_d7", "pll3", + CRU_BASE_TYPE_APBS, APB_SPARE11_REG, RT_BIT(6), RT_BIT(6), 0x0, 7, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll3_d8, "pll3_d8", "pll3", + CRU_BASE_TYPE_APBS, APB_SPARE11_REG, RT_BIT(7), RT_BIT(7), 0x0, 8, 1, RT_CLK_F_IGNORE_UNUSED); + +/* PLL3_DIV */ +static SPACEMIT_CCU_FACTOR(pll3_80, "pll3_80", "pll3_d8", 5, 1); +static SPACEMIT_CCU_FACTOR(pll3_40, "pll3_40", "pll3_d8", 10, 1); +static SPACEMIT_CCU_FACTOR(pll3_20, "pll3_20", "pll3_d8", 20, 1); + +/* PLL1_D8 */ +static SPACEMIT_CCU_GATE(pll1_d8_307p2, "pll1_d8_307p2", "pll1_d8", + CRU_BASE_TYPE_MPMU, MPMU_ACGR, RT_BIT(13), RT_BIT(13), 0x0, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_FACTOR(pll1_d32_76p8, "pll1_d32_76p8", "pll1_d8_307p2", 4, 1); +static SPACEMIT_CCU_FACTOR(pll1_d40_61p44, "pll1_d40_61p44", "pll1_d8_307p2", 5, 1); +static SPACEMIT_CCU_FACTOR(pll1_d16_153p6, "pll1_d16_153p6", "pll1_d8", 2, 1); +static SPACEMIT_CCU_GATE_FACTOR(pll1_d24_102p4, "pll1_d24_102p4", "pll1_d8", + CRU_BASE_TYPE_MPMU, MPMU_ACGR, RT_BIT(12), RT_BIT(12), 0x0, 3, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll1_d48_51p2, "pll1_d48_51p2", "pll1_d8", + CRU_BASE_TYPE_MPMU, MPMU_ACGR, RT_BIT(7), RT_BIT(7), 0x0, 6, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll1_d48_51p2_ap, "pll1_d48_51p2_ap", "pll1_d8", + CRU_BASE_TYPE_MPMU, MPMU_ACGR, RT_BIT(11), RT_BIT(11), 0x0, 6, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll1_m3d128_57p6, "pll1_m3d128_57p6", "pll1_d8", + CRU_BASE_TYPE_MPMU, MPMU_ACGR, RT_BIT(8), RT_BIT(8), 0x0, 16, 3, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll1_d96_25p6, "pll1_d96_25p6", "pll1_d8", + CRU_BASE_TYPE_MPMU, MPMU_ACGR, RT_BIT(4), RT_BIT(4), 0x0, 12, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll1_d192_12p8, "pll1_d192_12p8", "pll1_d8", + CRU_BASE_TYPE_MPMU, MPMU_ACGR, RT_BIT(3), RT_BIT(3), 0x0, 24, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll1_d192_12p8_wdt, "pll1_d192_12p8_wdt", "pll1_d8", + CRU_BASE_TYPE_MPMU, MPMU_ACGR, RT_BIT(19), RT_BIT(19), 0x0, 24, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll1_d384_6p4, "pll1_d384_6p4", "pll1_d8", + CRU_BASE_TYPE_MPMU, MPMU_ACGR, RT_BIT(2), RT_BIT(2), 0x0, 48, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_FACTOR(pll1_d768_3p2, "pll1_d768_3p2", "pll1_d384_6p4", 2, 1); +static SPACEMIT_CCU_FACTOR(pll1_d1536_1p6, "pll1_d1536_1p6", "pll1_d384_6p4", 4, 1); +static SPACEMIT_CCU_FACTOR(pll1_d3072_0p8, "pll1_d3072_0p8", "pll1_d384_6p4", 8, 1); +/* PLL1_D7 */ +static SPACEMIT_CCU_FACTOR(pll1_d7_351p08, "pll1_d7_351p08", "pll1_d7", 1, 1); +/* PLL1_D6 */ +static SPACEMIT_CCU_GATE(pll1_d6_409p6, "pll1_d6_409p6", "pll1_d6", + CRU_BASE_TYPE_MPMU, MPMU_ACGR, RT_BIT(0), RT_BIT(0), 0x0, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll1_d12_204p8, "pll1_d12_204p8", "pll1_d6", + CRU_BASE_TYPE_MPMU, MPMU_ACGR, RT_BIT(5), RT_BIT(5), 0x0, 2, 1, RT_CLK_F_IGNORE_UNUSED); +/* PLL1_D5 */ +static SPACEMIT_CCU_GATE(pll1_d5_491p52, "pll1_d5_491p52", "pll1_d5", + CRU_BASE_TYPE_MPMU, MPMU_ACGR, RT_BIT(21), RT_BIT(21), 0x0, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll1_d10_245p76, "pll1_d10_245p76", "pll1_d5", + CRU_BASE_TYPE_MPMU, MPMU_ACGR, RT_BIT(18), RT_BIT(18), 0x0, 2, 1, RT_CLK_F_IGNORE_UNUSED); +/* PLL1_D4 */ +static SPACEMIT_CCU_GATE(pll1_d4_614p4, "pll1_d4_614p4", "pll1_d4", + CRU_BASE_TYPE_MPMU, MPMU_ACGR, RT_BIT(15), RT_BIT(15), 0x0, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll1_d52_47p26, "pll1_d52_47p26", "pll1_d4", + CRU_BASE_TYPE_MPMU, MPMU_ACGR, RT_BIT(10), RT_BIT(10), 0x0, 13, 1, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_GATE_FACTOR(pll1_d78_31p5, "pll1_d78_31p5", "pll1_d4", + CRU_BASE_TYPE_MPMU, MPMU_ACGR, RT_BIT(6), RT_BIT(6), 0x0, 39, 2, RT_CLK_F_IGNORE_UNUSED); +/* PLL1_D3 */ +static SPACEMIT_CCU_GATE(pll1_d3_819p2, "pll1_d3_819p2", "pll1_d3", + CRU_BASE_TYPE_MPMU, MPMU_ACGR, RT_BIT(14), RT_BIT(14), 0x0, RT_CLK_F_IGNORE_UNUSED); +/* PLL1_D2 */ +static SPACEMIT_CCU_GATE(pll1_d2_1228p8, "pll1_d2_1228p8", "pll1_d2", + CRU_BASE_TYPE_MPMU, MPMU_ACGR, RT_BIT(16), RT_BIT(16), 0x0, RT_CLK_F_IGNORE_UNUSED); + +/* DPLL */ +static const struct ccu_dpll_rate_tbl dpll1_rate_tbl[] = +{ + DPLL_RATE(2400000000UL, 0x00, 0x00, 0x20, 0x2a, 0x32, 0x64, 0xdd, 0x50), /* 5000 ppm */ + DPLL_RATE(2400000000UL, 0x00, 0x3b, 0x20, 0x2a, 0x32, 0x64, 0xdd, 0x50), /* 5000 ppm + pre-setting */ +}; + +static const struct ccu_dpll_rate_tbl dpll2_rate_tbl[] = +{ + DPLL_RATE(3200000000UL, 0x55, 0x55, 0x3d, 0x2a, 0x43, 0x67, 0xdd, 0x50), /* 5000ppm */ +}; + +static SPACEMIT_CCU_DPLL(dpll1, "dpll1", &dpll1_rate_tbl, RT_ARRAY_SIZE(dpll1_rate_tbl), + CRU_BASE_TYPE_APMU, APMU_DPLL1_CLK_CTRL1, APMU_DPLL1_CLK_CTRL2, 0, RT_CLK_F_IGNORE_UNUSED); + +static SPACEMIT_CCU_DPLL(dpll2, "dpll2", &dpll2_rate_tbl, RT_ARRAY_SIZE(dpll2_rate_tbl), + CRU_BASE_TYPE_APMU, APMU_DPLL2_CLK_CTRL1, APMU_DPLL2_CLK_CTRL2, 0, RT_CLK_F_IGNORE_UNUSED); + +static const char *const dfc_lvl_parents[] = +{ + "dpll2", "dpll1" +}; + +static SPACEMIT_CCU_DIV_MUX(dfc_lvl0, "dfc_lvl0", dfc_lvl_parents, + CRU_BASE_TYPE_APMU, APMU_DFC_LEVEL0, 14, 2, 8, 1, 0); +static SPACEMIT_CCU_DIV_MUX(dfc_lvl1, "dfc_lvl1", dfc_lvl_parents, + CRU_BASE_TYPE_APMU, APMU_DFC_LEVEL1, 14, 2, 8, 1, 0); +static SPACEMIT_CCU_DIV_MUX(dfc_lvl2, "dfc_lvl2", dfc_lvl_parents, + CRU_BASE_TYPE_APMU, APMU_DFC_LEVEL2, 14, 2, 8, 1, 0); +static SPACEMIT_CCU_DIV_MUX(dfc_lvl3, "dfc_lvl3", dfc_lvl_parents, + CRU_BASE_TYPE_APMU, APMU_DFC_LEVEL3, 14, 2, 8, 1, 0); +static SPACEMIT_CCU_DIV_MUX(dfc_lvl4, "dfc_lvl4", dfc_lvl_parents, + CRU_BASE_TYPE_APMU, APMU_DFC_LEVEL4, 14, 2, 8, 1, 0); +static SPACEMIT_CCU_DIV_MUX(dfc_lvl5, "dfc_lvl5", dfc_lvl_parents, + CRU_BASE_TYPE_APMU, APMU_DFC_LEVEL5, 14, 2, 8, 1, 0); +static SPACEMIT_CCU_DIV_MUX(dfc_lvl6, "dfc_lvl6", dfc_lvl_parents, + CRU_BASE_TYPE_APMU, APMU_DFC_LEVEL6, 14, 2, 8, 1, 0); +static SPACEMIT_CCU_DIV_MUX(dfc_lvl7, "dfc_lvl7", dfc_lvl_parents, + CRU_BASE_TYPE_APMU, APMU_DFC_LEVEL7, 14, 2, 8, 1, 0); +static const char *const ddr_clk_parents[] = +{ + "dfc_lvl0", "dfc_lvl1", "dfc_lvl2", "dfc_lvl3", "dfc_lvl4", "dfc_lvl5", "dfc_lvl6", "dfc_lvl7" +}; +static SPACEMIT_CCU_DDR_FC(ddr, "ddr", ddr_clk_parents, + CRU_BASE_TYPE_APMU, APMU_DFC_AP, RT_BIT(0), 1, 3, 0); + +/* MPMU */ +static const struct ccu_ddn_info uart_ddn_mask_info = +{ + .factor = 2, + .num_mask = 0x1fff, + .den_mask = 0x1fff, + .num_shift = 16, + .den_shift = 0, +}; +static struct ccu_ddn_tbl slow_uart1_tbl[] = +{ + { .num = 125, .den = 24 }, /* rate = parent_rate * 24/125/2) */ +}; +static struct ccu_ddn_tbl slow_uart2_tbl[] = +{ + { .num = 6144, .den = 960 }, /* rate = parent_rate * 960/6144/2) */ +}; + +static SPACEMIT_CCU_GATE_NO_PARENT(slow_uart, "slow_uart", RT_NULL, + CRU_BASE_TYPE_MPMU, MPMU_ACGR, RT_BIT(1), RT_BIT(1), 0x0, 0); +static SPACEMIT_CCU_DDN(slow_uart1_14p74, "slow_uart1_14p74", "pll1_d16_153p6", + &uart_ddn_mask_info, &slow_uart1_tbl, RT_ARRAY_SIZE(slow_uart1_tbl), + CRU_BASE_TYPE_MPMU, MPMU_SUCCR, RT_CLK_F_IGNORE_UNUSED); +static SPACEMIT_CCU_DDN(slow_uart2_48, "slow_uart2_48", "pll1_d4_614p4", + &uart_ddn_mask_info, &slow_uart2_tbl, RT_ARRAY_SIZE(slow_uart2_tbl), + CRU_BASE_TYPE_MPMU, MPMU_SUCCR_1, RT_CLK_F_IGNORE_UNUSED); + +/* rate = parent_rate * den / num / 2) */ +static struct ccu_ddn_info mn_ddn_mask_info = +{ + .factor = 2, + .num_mask = 0x1fff, + .den_mask = 0x1fff, + .num_shift = 16, + .den_shift = 0, +}; + +/* parent_rate = 614400000Hz */ +static struct ccu_ddn_tbl mn_tbl[] = +{ + { .num = 6144, .den = 120 * 2 }, + { .num = 6144, .den = 200 * 2 }, + { .num = 6144, .den = 240 * 2 }, + { .num = 6144, .den = 250 * 2 }, + { .num = 6144, .den = 260 * 2 }, + { .num = 6144, .den = 270 * 2 }, + { .num = 6144, .den = 300 * 2 }, + { .num = 6144, .den = 480 * 2 }, +}; + +static const char *const mn_parent_names[] = +{ + "vctcxo_24", "pll1_d4_614p4" +}; + +static SPACEMIT_CCU_MUX_GATE(mn_src_clk, "mn_src_clk", mn_parent_names, + CRU_BASE_TYPE_MPMU, MPMU_PM_MN, 1, 1, RT_BIT(0), RT_BIT(0), 0x0, 0); + +static SPACEMIT_CCU_DDN(mn_clk, "mn_clk", "mn_src_clk", + &mn_ddn_mask_info, &mn_tbl, RT_ARRAY_SIZE(mn_tbl), CRU_BASE_TYPE_MPMU, MPMU_PM_MN_GPCR, 0); + +/* parent_rate = 600000000Hz */ +static struct ccu_ddn_tbl mn2_tbl[] = +{ + {.num = 6000, .den = 120 * 2}, + {.num = 6000, .den = 200 * 2}, + {.num = 6000, .den = 240 * 2}, + {.num = 6000, .den = 250 * 2}, + {.num = 6000, .den = 260 * 2}, + {.num = 6000, .den = 270 * 2}, + {.num = 6000, .den = 300 * 2}, + {.num = 6000, .den = 480 * 2}, +}; + +static const char *const mn2_parent_names[] = +{ + "vctcxo_24", "pll2_d5" +}; + +static SPACEMIT_CCU_MUX_GATE(mn2_src_clk, "mn2_src_clk", mn2_parent_names, + CRU_BASE_TYPE_MPMU, MPMU_PM_MN, 5, 1, RT_BIT(4), RT_BIT(4), 0x0, 0); + +static SPACEMIT_CCU_DDN(mn2_clk, "mn2_clk", "mn2_src_clk", + &mn_ddn_mask_info, &mn2_tbl, RT_ARRAY_SIZE(mn2_tbl), CRU_BASE_TYPE_MPMU, MPMU_PM_MN_GPCR2, 0); + +/* APBC */ +static const char *const uart_parent_names[] = +{ + "pll1_m3d128_57p6", "slow_uart1_14p74", "slow_uart2_48" +}; +static SPACEMIT_CCU_MUX_GATE(uart1_clk, "uart1_clk", uart_parent_names, + CRU_BASE_TYPE_APBC, APBC_UART1_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(uart2_clk, "uart2_clk", uart_parent_names, + CRU_BASE_TYPE_APBC, APBC_UART2_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(uart3_clk, "uart3_clk", uart_parent_names, + CRU_BASE_TYPE_APBC, APBC_UART3_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(uart4_clk, "uart4_clk", uart_parent_names, + CRU_BASE_TYPE_APBC, APBC_UART4_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(uart5_clk, "uart5_clk", uart_parent_names, + CRU_BASE_TYPE_APBC, APBC_UART5_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(uart6_clk, "uart6_clk", uart_parent_names, + CRU_BASE_TYPE_APBC, APBC_UART6_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(uart7_clk, "uart7_clk", uart_parent_names, + CRU_BASE_TYPE_APBC, APBC_UART7_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(uart8_clk, "uart8_clk", uart_parent_names, + CRU_BASE_TYPE_APBC, APBC_UART8_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(uart9_clk, "uart9_clk", uart_parent_names, + CRU_BASE_TYPE_APBC, APBC_UART9_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_GATE(gpio_clk, "gpio_clk", "vctcxo_24", + CRU_BASE_TYPE_APBC, APBC_GPIO_CLK_RST, 0x3, 0x3, 0x0, 0); +static const char *pwm_parent_names[] = +{ + "pll1_d192_12p8", "clk_32k" +}; +static SPACEMIT_CCU_MUX_GATE(pwm0_clk, "pwm0_clk", pwm_parent_names, + CRU_BASE_TYPE_APBC, APBC_PWM0_CLK_RST, 4, 3, 0x2, 0x2, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(pwm1_clk, "pwm1_clk", pwm_parent_names, + CRU_BASE_TYPE_APBC, APBC_PWM1_CLK_RST, 4, 3, 0x2, 0x2, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(pwm2_clk, "pwm2_clk", pwm_parent_names, + CRU_BASE_TYPE_APBC, APBC_PWM2_CLK_RST, 4, 3, 0x2, 0x2, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(pwm3_clk, "pwm3_clk", pwm_parent_names, + CRU_BASE_TYPE_APBC, APBC_PWM3_CLK_RST, 4, 3, 0x2, 0x2, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(pwm4_clk, "pwm4_clk", pwm_parent_names, + CRU_BASE_TYPE_APBC, APBC_PWM4_CLK_RST, 4, 3, 0x2, 0x2, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(pwm5_clk, "pwm5_clk", pwm_parent_names, + CRU_BASE_TYPE_APBC, APBC_PWM5_CLK_RST, 4, 3, 0x2, 0x2, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(pwm6_clk, "pwm6_clk", pwm_parent_names, + CRU_BASE_TYPE_APBC, APBC_PWM6_CLK_RST, 4, 3, 0x2, 0x2, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(pwm7_clk, "pwm7_clk", pwm_parent_names, + CRU_BASE_TYPE_APBC, APBC_PWM7_CLK_RST, 4, 3, 0x2, 0x2, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(pwm8_clk, "pwm8_clk", pwm_parent_names, + CRU_BASE_TYPE_APBC, APBC_PWM8_CLK_RST, 4, 3, 0x2, 0x2, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(pwm9_clk, "pwm9_clk", pwm_parent_names, + CRU_BASE_TYPE_APBC, APBC_PWM9_CLK_RST, 4, 3, 0x2, 0x2, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(pwm10_clk, "pwm10_clk", pwm_parent_names, + CRU_BASE_TYPE_APBC, APBC_PWM10_CLK_RST, 4, 3, 0x2, 0x2, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(pwm11_clk, "pwm11_clk", pwm_parent_names, + CRU_BASE_TYPE_APBC, APBC_PWM11_CLK_RST, 4, 3, 0x2, 0x2, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(pwm12_clk, "pwm12_clk", pwm_parent_names, + CRU_BASE_TYPE_APBC, APBC_PWM12_CLK_RST, 4, 3, 0x2, 0x2, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(pwm13_clk, "pwm13_clk", pwm_parent_names, + CRU_BASE_TYPE_APBC, APBC_PWM13_CLK_RST, 4, 3, 0x2, 0x2, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(pwm14_clk, "pwm14_clk", pwm_parent_names, + CRU_BASE_TYPE_APBC, APBC_PWM14_CLK_RST, 4, 3, 0x2, 0x2, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(pwm15_clk, "pwm15_clk", pwm_parent_names, + CRU_BASE_TYPE_APBC, APBC_PWM15_CLK_RST, 4, 3, 0x2, 0x2, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(pwm16_clk, "pwm16_clk", pwm_parent_names, + CRU_BASE_TYPE_APBC, APBC_PWM16_CLK_RST, 4, 3, 0x2, 0x2, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(pwm17_clk, "pwm17_clk", pwm_parent_names, + CRU_BASE_TYPE_APBC, APBC_PWM17_CLK_RST, 4, 3, 0x2, 0x2, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(pwm18_clk, "pwm18_clk", pwm_parent_names, + CRU_BASE_TYPE_APBC, APBC_PWM18_CLK_RST, 4, 3, 0x2, 0x2, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(pwm19_clk, "pwm19_clk", pwm_parent_names, + CRU_BASE_TYPE_APBC, APBC_PWM19_CLK_RST, 4, 3, 0x2, 0x2, 0x0, 0); +static const char *ssp_parent_names[] = +{ + "pll1_d384_6p4", "pll1_d192_12p8", "pll1_d96_25p6", "pll1_d48_51p2", + "pll1_d768_3p2", "pll1_d1536_1p6", "pll1_d3072_0p8", "vctcxo_1" +}; +static SPACEMIT_CCU_MUX_GATE(ssp3_clk, "ssp3_clk", ssp_parent_names, + CRU_BASE_TYPE_APBC, APBC_SSP3_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_GATE(rtc_clk, "rtc_clk", "clk_32k", + CRU_BASE_TYPE_APBC, APBC_RTC_CLK_RST, 0x83, 0x83, 0x0, 0); +static const char *twsi_parent_names[] = +{ + "pll1_d78_31p5", "pll1_d48_51p2", "pll1_d40_61p44" +}; +static SPACEMIT_CCU_MUX_GATE(twsi0_clk, "twsi0_clk", twsi_parent_names, + CRU_BASE_TYPE_APBC, APBC_TWSI0_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(twsi1_clk, "twsi1_clk", twsi_parent_names, + CRU_BASE_TYPE_APBC, APBC_TWSI1_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(twsi2_clk, "twsi2_clk", twsi_parent_names, + CRU_BASE_TYPE_APBC, APBC_TWSI2_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(twsi4_clk, "twsi4_clk", twsi_parent_names, + CRU_BASE_TYPE_APBC, APBC_TWSI4_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(twsi5_clk, "twsi5_clk", twsi_parent_names, + CRU_BASE_TYPE_APBC, APBC_TWSI5_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(twsi6_clk, "twsi6_clk", twsi_parent_names, + CRU_BASE_TYPE_APBC, APBC_TWSI6_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(twsi7_clk, "twsi7_clk", twsi_parent_names, + CRU_BASE_TYPE_APBC, APBC_TWSI7_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(twsi8_clk, "twsi8_clk", twsi_parent_names, + CRU_BASE_TYPE_APBC, APBC_TWSI8_CLK_RST, 4, 3, 0x7, 0x3, 0x4, 0); +static const char *timer_parent_names[] = +{ + "pll1_d192_12p8", "clk_32k", "pll1_d384_6p4", "vctcxo_3", "vctcxo_1" +}; +static SPACEMIT_CCU_MUX_GATE(timers1_clk, "timers1_clk", timer_parent_names, + CRU_BASE_TYPE_APBC, APBC_TIMERS1_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(timers2_clk, "timers2_clk", timer_parent_names, + CRU_BASE_TYPE_APBC, APBC_TIMERS2_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_GATE(aib_clk, "aib_clk", "vctcxo_24", + CRU_BASE_TYPE_APBC, APBC_AIB_CLK_RST, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(onewire_clk, "onewire_clk", RT_NULL, + CRU_BASE_TYPE_APBC, APBC_ONEWIRE_CLK_RST, 0x3, 0x3, 0x0, 0); + +static SPACEMIT_CCU_GATE_FACTOR(i2s_sysclk, "i2s_sysclk", "pll1_d8_307p2", + CRU_BASE_TYPE_MPMU, MPMU_ISCCR, RT_BIT(31), RT_BIT(31), 0x0, 200, 1, 0); +static SPACEMIT_CCU_GATE_FACTOR(i2s_bclk, "i2s_bclk", "i2s_sysclk", + CRU_BASE_TYPE_MPMU, MPMU_ISCCR, RT_BIT(29), RT_BIT(29), 0x0, 1, 1, 0); +static const char *sspa_parent_names[] = +{ + "pll1_d384_6p4", "pll1_d192_12p8", "pll1_d96_25p6", + "pll1_d48_51p2", "pll1_d768_3p2", "pll1_d1536_1p6", "pll1_d3072_0p8", "i2s_bclk" +}; +static SPACEMIT_CCU_MUX_GATE(sspa0_clk, "sspa0_clk", sspa_parent_names, + CRU_BASE_TYPE_APBC, APBC_SSPA0_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_MUX_GATE(sspa1_clk, "sspa1_clk", sspa_parent_names, + CRU_BASE_TYPE_APBC, APBC_SSPA1_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(dro_clk, "dro_clk", RT_NULL, + CRU_BASE_TYPE_APBC, APBC_DRO_CLK_RST, 0x1, 0x1, 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(ir_clk, "ir_clk", RT_NULL, + CRU_BASE_TYPE_APBC, APBC_IR_CLK_RST, 0x1, 0x1, 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(tsen_clk, "tsen_clk", RT_NULL, + CRU_BASE_TYPE_APBC, APBC_TSEN_CLK_RST, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(ipc_ap2aud_clk, "ipc_ap2aud_clk", RT_NULL, + CRU_BASE_TYPE_APBC, APBC_IPC_AP2AUD_CLK_RST, 0x3, 0x3, 0x0, 0); +static const char *can_parent_names[] = +{ + "pll3_20", "pll3_40", "pll3_80" +}; +static SPACEMIT_CCU_MUX_GATE(can0_clk, "can0_clk", can_parent_names, + CRU_BASE_TYPE_APBC, APBC_CAN0_CLK_RST, 4, 3, RT_BIT(1), RT_BIT(1), 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(can0_bus_clk, "can0_bus_clk", RT_NULL, + CRU_BASE_TYPE_APBC, APBC_CAN0_CLK_RST, RT_BIT(0), RT_BIT(0), 0x0, 0); + +/* MPMU */ +static SPACEMIT_CCU_GATE(wdt_clk, "wdt_clk", "pll1_d96_25p6", + CRU_BASE_TYPE_MPMU, MPMU_WDTPCR, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(ripc_clk, "ripc_clk", RT_NULL, + CRU_BASE_TYPE_MPMU, MPMU_RIPCCR, 0x3, 0x3, 0x0, 0); + +/* APMU */ +static const char *const jpg_parent_names[] = +{ + "pll1_d4_614p4", "pll1_d6_409p6", "pll1_d5_491p52", "pll1_d3_819p2", + "pll1_d2_1228p8", "pll2_d4", "pll2_d3" +}; +static SPACEMIT_CCU_DIV_FC_MUX_GATE(jpg_clk, "jpg_clk", jpg_parent_names, + CRU_BASE_TYPE_APMU, APMU_JPG_CLK_RES_CTRL, + 5, 3, RT_BIT(15), 2, 3, RT_BIT(1), RT_BIT(1), 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(jpg_4kafbc_clk, "jpg_4kafbc_clk", RT_NULL, + CRU_BASE_TYPE_APMU, APMU_JPG_CLK_RES_CTRL, RT_BIT(16), RT_BIT(16), 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(jpg_2kafbc_clk, "jpg_2kafbc_clk", RT_NULL, + CRU_BASE_TYPE_APMU, APMU_JPG_CLK_RES_CTRL, RT_BIT(17), RT_BIT(17), 0x0, 0); +static const char *const ccic2phy_parent_names[] = +{ + "pll1_d24_102p4", "pll1_d48_51p2_ap" +}; +static SPACEMIT_CCU_MUX_GATE(ccic2phy_clk, "ccic2phy_clk", ccic2phy_parent_names, + CRU_BASE_TYPE_APMU, APMU_CSI_CCIC2_CLK_RES_CTRL, 7, 1, RT_BIT(5), RT_BIT(5), 0x0, 0); +static const char *const ccic3phy_parent_names[] = +{ + "pll1_d24_102p4", "pll1_d48_51p2_ap" +}; +static SPACEMIT_CCU_MUX_GATE(ccic3phy_clk, "ccic3phy_clk", ccic3phy_parent_names, + CRU_BASE_TYPE_APMU, APMU_CSI_CCIC2_CLK_RES_CTRL, 31, 1, RT_BIT(30), RT_BIT(30), 0x0, 0); +static const char *const csi_parent_names[] = +{ + "pll1_d5_491p52", "pll1_d6_409p6", "pll1_d4_614p4", "pll1_d3_819p2", + "pll2_d2", "pll2_d3", "pll2_d4", "pll1_d2_1228p8" +}; +static SPACEMIT_CCU_DIV_FC_MUX_GATE(csi_clk, "csi_clk", csi_parent_names, + CRU_BASE_TYPE_APMU, APMU_CSI_CCIC2_CLK_RES_CTRL, + 20, 3, RT_BIT(15), 16, 3, RT_BIT(4), RT_BIT(4), 0x0, 0); +static const char *const camm_parent_names[] = +{ + "pll1_d8_307p2", "pll2_d5", "pll1_d6_409p6", "vctcxo_24" +}; +static SPACEMIT_CCU_DIV_MUX_GATE(camm0_clk, "camm0_clk", camm_parent_names, + CRU_BASE_TYPE_APMU, APMU_CSI_CCIC2_CLK_RES_CTRL, + 23, 4, 8, 2, RT_BIT(28), RT_BIT(28), 0x0, 0); +static SPACEMIT_CCU_DIV_MUX_GATE(camm1_clk, "camm1_clk", camm_parent_names, + CRU_BASE_TYPE_APMU, APMU_CSI_CCIC2_CLK_RES_CTRL, + 23, 4, 8, 2, RT_BIT(6), RT_BIT(6), 0x0, 0); +static SPACEMIT_CCU_DIV_MUX_GATE(camm2_clk, "camm2_clk", camm_parent_names, + CRU_BASE_TYPE_APMU, APMU_CSI_CCIC2_CLK_RES_CTRL, + 23, 4, 8, 2, RT_BIT(3), RT_BIT(3), 0x0, 0); +static const char *const isp_cpp_parent_names[] = +{ + "pll1_d8_307p2", "pll1_d6_409p6" +}; +static SPACEMIT_CCU_DIV_MUX_GATE(isp_cpp_clk, "isp_cpp_clk", isp_cpp_parent_names, + CRU_BASE_TYPE_APMU, APMU_ISP_CLK_RES_CTRL, + 24, 2, 26, 1, RT_BIT(28), RT_BIT(28), 0x0, 0); +static const char *const isp_bus_parent_names[] = +{ + "pll1_d6_409p6", "pll1_d5_491p52", "pll1_d8_307p2", "pll1_d10_245p76" +}; +static SPACEMIT_CCU_DIV_FC_MUX_GATE(isp_bus_clk, "isp_bus_clk", isp_bus_parent_names, + CRU_BASE_TYPE_APMU, APMU_ISP_CLK_RES_CTRL, + 18, 3, RT_BIT(23), 21, 2, RT_BIT(17), RT_BIT(17), 0x0, 0); +static const char *const isp_parent_names[] = +{ + "pll1_d6_409p6", "pll1_d5_491p52", "pll1_d4_614p4", "pll1_d8_307p2" +}; +static SPACEMIT_CCU_DIV_FC_MUX_GATE(isp_clk, "isp_clk", isp_parent_names, + CRU_BASE_TYPE_APMU, APMU_ISP_CLK_RES_CTRL, + 4, 3, RT_BIT(7), 8, 2, RT_BIT(1), RT_BIT(1), 0x0, 0); +static const char *const dpumclk_parent_names[] = +{ + "pll1_d6_409p6", "pll1_d5_491p52", "pll1_d4_614p4", "pll1_d8_307p2" +}; +static SPACEMIT_CCU_DIV2_FC_MUX_GATE(dpu_mclk, "dpu_mclk", dpumclk_parent_names, + CRU_BASE_TYPE_APMU, APMU_LCD_CLK_RES_CTRL1, APMU_LCD_CLK_RES_CTRL2, + 1, 4, RT_BIT(29), 5, 3, RT_BIT(0), RT_BIT(0), 0x0, 0); +static const char *const dpuesc_parent_names[] = +{ + "pll1_d48_51p2_ap", "pll1_d52_47p26", "pll1_d96_25p6", "pll1_d32_76p8" +}; +static SPACEMIT_CCU_MUX_GATE(dpu_esc_clk, "dpu_esc_clk", dpuesc_parent_names, + CRU_BASE_TYPE_APMU, APMU_LCD_CLK_RES_CTRL1, 0, 2, RT_BIT(2), RT_BIT(2), 0x0, 0); +static const char *const dpubit_parent_names[] = +{ + "pll1_d3_819p2", "pll2_d2", "pll2_d3", + "pll1_d2_1228p8", "pll2_d4", "pll2_d5", "pll2_d8", "pll2_d8" +}; +static SPACEMIT_CCU_DIV_FC_MUX_GATE(dpu_bit_clk, "dpu_bit_clk", dpubit_parent_names, + CRU_BASE_TYPE_APMU, APMU_LCD_CLK_RES_CTRL1, + 17, 3, RT_BIT(31), 20, 3, RT_BIT(16), RT_BIT(16), 0x0, 0); +static const char *const dpupx_parent_names[] = +{ + "pll1_d6_409p6", "pll1_d5_491p52", "pll1_d4_614p4", "pll1_d8_307p2", "pll2_d7", "pll2_d8" +}; +static SPACEMIT_CCU_DIV2_FC_MUX_GATE(dpu_pxclk, "dpu_pxclk", dpupx_parent_names, + CRU_BASE_TYPE_APMU, APMU_LCD_CLK_RES_CTRL1, APMU_LCD_CLK_RES_CTRL2, + 17, 4, RT_BIT(30), 21, 3, RT_BIT(16), RT_BIT(16), 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(dpu_hclk, "dpu_hclk", RT_NULL, + CRU_BASE_TYPE_APMU, APMU_LCD_CLK_RES_CTRL1, RT_BIT(5), RT_BIT(5), 0x0, 0); +static const char *const dpu_spi_parent_names[] = +{ + "pll1_d8_307p2", "pll1_d6_409p6", "pll1_d10_245p76", "pll1_d11_223p4", + "pll1_d13_189", "pll1_d23_106p8", "pll2_d3", "pll2_d5" +}; +static SPACEMIT_CCU_DIV_FC_MUX_GATE(dpu_spi_clk, "dpu_spi_clk", dpu_spi_parent_names, + CRU_BASE_TYPE_APMU, APMU_LCD_SPI_CLK_RES_CTRL, + 8, 3, RT_BIT(7), 12, 3, RT_BIT(1), RT_BIT(1), 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(dpu_spi_hbus_clk, "dpu_spi_hbus_clk", RT_NULL, + CRU_BASE_TYPE_APMU, APMU_LCD_SPI_CLK_RES_CTRL, RT_BIT(3), RT_BIT(3), 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(dpu_spi_bus_clk, "dpu_spi_bus_clk", RT_NULL, + CRU_BASE_TYPE_APMU, APMU_LCD_SPI_CLK_RES_CTRL, RT_BIT(5), RT_BIT(5), 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(dpu_spi_aclk, "dpu_spi_aclk", RT_NULL, + CRU_BASE_TYPE_APMU, APMU_LCD_SPI_CLK_RES_CTRL, RT_BIT(6), RT_BIT(6), 0x0, 0); +static const char *const v2d_parent_names[] = +{ + "pll1_d5_491p52", "pll1_d6_409p6", "pll1_d8_307p2", "pll1_d4_614p4", +}; +static SPACEMIT_CCU_DIV_FC_MUX_GATE(v2d_clk, "v2d_clk", v2d_parent_names, + CRU_BASE_TYPE_APMU, APMU_LCD_CLK_RES_CTRL1, + 9, 3, RT_BIT(28), 12, 2, RT_BIT(8), RT_BIT(8), 0x0, 0); +static const char *const ccic_4x_parent_names[] = +{ + "pll1_d5_491p52", "pll1_d6_409p6", "pll1_d4_614p4", "pll1_d3_819p2", + "pll2_d2", "pll2_d3", "pll2_d4", "pll1_d2_1228p8" +}; +static SPACEMIT_CCU_DIV_FC_MUX_GATE(ccic_4x_clk, "ccic_4x_clk", ccic_4x_parent_names, + CRU_BASE_TYPE_APMU, APMU_CCIC_CLK_RES_CTRL, + 18, 3, RT_BIT(15), 23, 2, RT_BIT(4), RT_BIT(4), 0x0, 0); +static const char *const ccic1phy_parent_names[] = +{ + "pll1_d24_102p4", "pll1_d48_51p2_ap" +}; +static SPACEMIT_CCU_MUX_GATE(ccic1phy_clk, "ccic1phy_clk", ccic1phy_parent_names, + CRU_BASE_TYPE_APMU, APMU_CCIC_CLK_RES_CTRL, 7, 1, RT_BIT(5), RT_BIT(5), 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(sdh_axi_aclk, "sdh_axi_aclk", RT_NULL, + CRU_BASE_TYPE_APMU, APMU_SDH0_CLK_RES_CTRL, RT_BIT(3), RT_BIT(3), 0x0, 0); +static const char *const sdh01_parent_names[] = +{ + "pll1_d6_409p6", "pll1_d4_614p4", "pll2_d8", "pll2_d5", + "pll1_d11_223p4", "pll1_d13_189", "pll1_d23_106p8" +}; + +static SPACEMIT_CCU_DIV_FC_MUX_GATE(sdh0_clk, "sdh0_clk", sdh01_parent_names, + CRU_BASE_TYPE_APMU, APMU_SDH0_CLK_RES_CTRL, + 8, 3, RT_BIT(11), 5, 3, RT_BIT(4), RT_BIT(4), 0x0, 0); +static SPACEMIT_CCU_DIV_FC_MUX_GATE(sdh1_clk, "sdh1_clk", sdh01_parent_names, + CRU_BASE_TYPE_APMU, APMU_SDH1_CLK_RES_CTRL, + 8, 3, RT_BIT(11), 5, 3, RT_BIT(4), RT_BIT(4), 0x0, 0); +static const char *const sdh2_parent_names[] = +{ + "pll1_d6_409p6", "pll1_d4_614p4", "pll2_d8", "pll1_d3_819p2", + "pll1_d11_223p4", "pll1_d13_189", "pll1_d23_106p8" +}; + +static SPACEMIT_CCU_DIV_FC_MUX_GATE(sdh2_clk, "sdh2_clk", sdh2_parent_names, + CRU_BASE_TYPE_APMU, APMU_SDH2_CLK_RES_CTRL, + 8, 3, RT_BIT(11), 5, 3, RT_BIT(4), RT_BIT(4), 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(usb_axi_clk, "usb_axi_clk", RT_NULL, + CRU_BASE_TYPE_APMU, APMU_USB_CLK_RES_CTRL, RT_BIT(1), RT_BIT(1), 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(usb_p1_aclk, "usb_p1_aclk", RT_NULL, + CRU_BASE_TYPE_APMU, APMU_USB_CLK_RES_CTRL, RT_BIT(5), RT_BIT(5), 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(usb30_clk, "usb30_clk", RT_NULL, + CRU_BASE_TYPE_APMU, APMU_USB_CLK_RES_CTRL, RT_BIT(8), RT_BIT(8), 0x0, 0); +static const char *const qspi_parent_names[] = +{ + "pll1_d6_409p6", "pll2_d8", "pll1_d8_307p2", "pll1_d10_245p76", + "pll1_d11_223p4", "pll1_d23_106p8", "pll1_d5_491p52", "pll1_d13_189" +}; +static SPACEMIT_CCU_DIV_MUX_GATE(qspi_clk, "qspi_clk", qspi_parent_names, + CRU_BASE_TYPE_APMU, APMU_QSPI_CLK_RES_CTRL, + 9, 3, 6, 3, RT_BIT(4), RT_BIT(4), 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(qspi_bus_clk, "qspi_bus_clk", RT_NULL, + CRU_BASE_TYPE_APMU, APMU_QSPI_CLK_RES_CTRL, RT_BIT(3), RT_BIT(3), 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(dma_clk, "dma_clk", RT_NULL, + CRU_BASE_TYPE_APMU, APMU_DMA_CLK_RES_CTRL, RT_BIT(3), RT_BIT(3), 0x0, 0); +static const char *const aes_parent_names[] = +{ + "pll1_d12_204p8", "pll1_d24_102p4" +}; +static SPACEMIT_CCU_MUX_GATE(aes_clk, "aes_clk", aes_parent_names, + CRU_BASE_TYPE_APMU, APMU_AES_CLK_RES_CTRL, 6, 1, RT_BIT(5), RT_BIT(5), 0x0, 0); +static const char *const vpu_parent_names[] = +{ + "pll1_d4_614p4", "pll1_d5_491p52", "pll1_d3_819p2", "pll1_d6_409p6", + "pll3_d6", "pll2_d3", "pll2_d4", "pll2_d5" +}; +static SPACEMIT_CCU_DIV_FC_MUX_GATE(vpu_clk, "vpu_clk", vpu_parent_names, + CRU_BASE_TYPE_APMU, APMU_VPU_CLK_RES_CTRL, + 13, 3, RT_BIT(21), 10, 3, RT_BIT(3), RT_BIT(3), 0x0, 0); +static const char *const gpu_parent_names[] = +{ + "pll1_d4_614p4", "pll1_d5_491p52", "pll1_d3_819p2", "pll1_d6_409p6", + "pll3_d6", "pll2_d3", "pll2_d4", "pll2_d5" +}; +static SPACEMIT_CCU_DIV_FC_MUX_GATE(gpu_clk, "gpu_clk", gpu_parent_names, + CRU_BASE_TYPE_APMU, APMU_GPU_CLK_RES_CTRL, + 12, 3, RT_BIT(15), 18, 3, RT_BIT(4), RT_BIT(4), 0x0, 0); +static const char *const emmc_parent_names[] = +{ + "pll1_d6_409p6", "pll1_d4_614p4", "pll1_d52_47p26", "pll1_d3_819p2" +}; +static SPACEMIT_CCU_DIV_FC_MUX_GATE(emmc_clk, "emmc_clk", emmc_parent_names, + CRU_BASE_TYPE_APMU, APMU_PMUA_EM_CLK_RES_CTRL, + 8, 3, RT_BIT(11), 6, 2, 0x18, 0x18, 0x0, 0); +static SPACEMIT_CCU_DIV_GATE(emmc_x_clk, "emmc_x_clk", "pll1_d2_1228p8", + CRU_BASE_TYPE_APMU, APMU_PMUA_EM_CLK_RES_CTRL, + 12, 3, RT_BIT(15), RT_BIT(15), 0x0, 0); +static const char *const audio_parent_names[] = +{ + "pll1_aud_245p7", "pll1_d8_307p2", "pll1_d6_409p6" +}; +static SPACEMIT_CCU_DIV_FC_MUX_GATE(audio_clk, "audio_clk", audio_parent_names, + CRU_BASE_TYPE_APMU, APMU_AUDIO_CLK_RES_CTRL, + 4, 3, RT_BIT(15), 7, 3, RT_BIT(12), RT_BIT(12), 0x0, 0); +static const char *const hdmi_parent_names[] = +{ + "pll1_d6_409p6", "pll1_d5_491p52", "pll1_d4_614p4", "pll1_d8_307p2" +}; +static SPACEMIT_CCU_DIV_FC_MUX_GATE(hdmi_mclk, "hdmi_mclk", hdmi_parent_names, + CRU_BASE_TYPE_APMU, APMU_HDMI_CLK_RES_CTRL, + 1, 4, RT_BIT(29), 5, 3, RT_BIT(0), RT_BIT(0), 0x0, 0); +static const char *const cci550_parent_names[] = +{ + "pll1_d5_491p52", "pll1_d4_614p4", "pll1_d3_819p2", "pll2_d3" +}; +static SPACEMIT_CCU_DIV_FC_MUX(cci550_clk, "cci550_clk", cci550_parent_names, + CRU_BASE_TYPE_APMU, APMU_CCI550_CLK_CTRL, 8, 3, RT_BIT(12), 0, 2, 0); +static const char *const pmua_aclk_parent_names[] = +{ + "pll1_d10_245p76", "pll1_d8_307p2" +}; +static SPACEMIT_CCU_DIV_FC_MUX(pmua_aclk, "pmua_aclk", pmua_aclk_parent_names, + CRU_BASE_TYPE_APMU, APMU_ACLK_CLK_CTRL, 1, 2, RT_BIT(4), 0, 1, 0); +static const char *const cpu_c0_hi_parent_names[] = +{ + "pll3_d2", "pll3_d1" +}; +static SPACEMIT_CCU_MUX(cpu_c0_hi_clk, "cpu_c0_hi_clk", cpu_c0_hi_parent_names, + CRU_BASE_TYPE_APMU, APMU_CPU_C0_CLK_CTRL, 13, 1, 0); +static const char *const cpu_c0_parent_names[] = +{ + "pll1_d4_614p4", "pll1_d3_819p2", "pll1_d6_409p6", + "pll1_d5_491p52", "pll1_d2_1228p8", "pll3_d3", "pll2_d3", "cpu_c0_hi_clk" +}; +static SPACEMIT_CCU_MUX_FC(cpu_c0_core_clk, "cpu_c0_core_clk", cpu_c0_parent_names, + CRU_BASE_TYPE_APMU, APMU_CPU_C0_CLK_CTRL, RT_BIT(12), 0, 3, 0); +static SPACEMIT_CCU_DIV(cpu_c0_ace_clk, "cpu_c0_ace_clk", "cpu_c0_core_clk", + CRU_BASE_TYPE_APMU, APMU_CPU_C0_CLK_CTRL, 6, 3, 0); +static SPACEMIT_CCU_DIV(cpu_c0_tcm_clk, "cpu_c0_tcm_clk", "cpu_c0_core_clk", + CRU_BASE_TYPE_APMU, APMU_CPU_C0_CLK_CTRL, 9, 3, 0); +static const char *const cpu_c1_hi_parent_names[] = +{ + "pll3_d2", "pll3_d1" +}; +static SPACEMIT_CCU_MUX(cpu_c1_hi_clk, "cpu_c1_hi_clk", cpu_c1_hi_parent_names, + CRU_BASE_TYPE_APMU, APMU_CPU_C1_CLK_CTRL, 13, 1, 0); +static const char *const cpu_c1_parent_names[] = +{ + "pll1_d4_614p4", "pll1_d3_819p2", "pll1_d6_409p6", + "pll1_d5_491p52", "pll1_d2_1228p8", "pll3_d3", "pll2_d3", "cpu_c1_hi_clk" +}; +static SPACEMIT_CCU_MUX_FC(cpu_c1_pclk, "cpu_c1_pclk", cpu_c1_parent_names, + CRU_BASE_TYPE_APMU, APMU_CPU_C1_CLK_CTRL, RT_BIT(12), 0, 3, 0); +static SPACEMIT_CCU_DIV(cpu_c1_ace_clk, "cpu_c1_ace_clk", "cpu_c1_pclk", + CRU_BASE_TYPE_APMU, APMU_CPU_C1_CLK_CTRL, 6, 3, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(pcie0_clk, "pcie0_clk", RT_NULL, + CRU_BASE_TYPE_APMU, APMU_PCIE_CLK_RES_CTRL_0, 0x7, 0x7, 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(pcie1_clk, "pcie1_clk", RT_NULL, + CRU_BASE_TYPE_APMU, APMU_PCIE_CLK_RES_CTRL_1, 0x7, 0x7, 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(pcie2_clk, "pcie2_clk", RT_NULL, + CRU_BASE_TYPE_APMU, APMU_PCIE_CLK_RES_CTRL_2, 0x7, 0x7, 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(emac0_bus_clk, "emac0_bus_clk", RT_NULL, + CRU_BASE_TYPE_APMU, APMU_EMAC0_CLK_RES_CTRL, RT_BIT(0), RT_BIT(0), 0x0, 0); +static SPACEMIT_CCU_GATE(emac0_ptp_clk, "emac0_ptp_clk", "pll2_d6", + CRU_BASE_TYPE_APMU, APMU_EMAC0_CLK_RES_CTRL, RT_BIT(15), RT_BIT(15), 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(emac1_bus_clk, "emac1_bus_clk", RT_NULL, + CRU_BASE_TYPE_APMU, APMU_EMAC1_CLK_RES_CTRL, RT_BIT(0), RT_BIT(0), 0x0, 0); +static SPACEMIT_CCU_GATE(emac1_ptp_clk, "emac1_ptp_clk", "pll2_d6", + CRU_BASE_TYPE_APMU, APMU_EMAC1_CLK_RES_CTRL, RT_BIT(15), RT_BIT(15), 0x0, 0); + +/* APBC2 */ +static const char *const uart1_sec_parent_names[] = +{ + "pll1_m3d128_57p6", "slow_uart1_14p74", "slow_uart2_48" +}; +static SPACEMIT_CCU_MUX_GATE(uart1_sec_clk, "uart1_sec_clk", uart1_sec_parent_names, + CRU_BASE_TYPE_APBC2, APBC2_UART1_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); + +static const char *ssp2_sec_parent_names[] = +{ + "pll1_d384_6p4", "pll1_d192_12p8", "pll1_d96_25p6", + "pll1_d48_51p2", "pll1_d768_3p2", "pll1_d1536_1p6", "pll1_d3072_0p8" +}; +static SPACEMIT_CCU_MUX_GATE(ssp2_sec_clk, "ssp2_sec_clk", ssp2_sec_parent_names, + CRU_BASE_TYPE_APBC2, APBC2_SSP2_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static const char *twsi3_sec_parent_names[] = +{ + "pll1_d78_31p5", "pll1_d48_51p2", "pll1_d40_61p44" +}; +static SPACEMIT_CCU_MUX_GATE(twsi3_sec_clk, "twsi3_sec_clk", twsi3_sec_parent_names, + CRU_BASE_TYPE_APBC2, APBC2_TWSI3_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_GATE(rtc_sec_clk, "rtc_sec_clk", "clk_32k", + CRU_BASE_TYPE_APBC2, APBC2_RTC_CLK_RST, 0x83, 0x83, 0x0, 0); +static const char *timer_sec_parent_names[] = +{ + "pll1_d192_12p8", "clk_32k", "pll1_d384_6p4", "vctcxo_3", "vctcxo_1" +}; +static SPACEMIT_CCU_MUX_GATE(timers0_sec_clk, "timers0_sec_clk", timer_sec_parent_names, + CRU_BASE_TYPE_APBC2, APBC2_TIMERS0_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static const char *kpc_sec_parent_names[] = +{ + "pll1_d192_12p8", "clk_32k", "pll1_d384_6p4", "vctcxo_3", "vctcxo_1" +}; +static SPACEMIT_CCU_MUX_GATE(kpc_sec_clk, "kpc_sec_clk", kpc_sec_parent_names, + CRU_BASE_TYPE_APBC2, APBC2_KPC_CLK_RST, 4, 3, 0x3, 0x3, 0x0, 0); +static SPACEMIT_CCU_GATE(gpio_sec_clk, "gpio_sec_clk", "vctcxo_24", + CRU_BASE_TYPE_APBC2, APBC2_GPIO_CLK_RST, 0x3, 0x3, 0x0, 0); + +static const char *const apb_parent_names[] = +{ + "pll1_d96_25p6", "pll1_d48_51p2", "pll1_d96_25p6", "pll1_d24_102p4" +}; +static SPACEMIT_CCU_MUX(apb_clk, "apb_clk", apb_parent_names, + CRU_BASE_TYPE_MPMU, MPMU_APBCSCR, 0, 2, 0); +/* RCPU */ +static const char *rhdmi_audio_parent_names[] = +{ + "pll1_aud_24p5", "pll1_aud_245p7" +}; +static SPACEMIT_CCU_DIV_MUX_GATE(rhdmi_audio_clk, "rhdmi_audio_clk", rhdmi_audio_parent_names, + CRU_BASE_TYPE_RCPU, RCPU_HDMI_CLK_RST, 4, 11, 16, 2, 0x6, 0x6, 0x0, 0); + +static const char *rcan_parent_names[] = +{ + "pll3_20", "pll3_40", "pll3_80" +}; +static SPACEMIT_CCU_DIV_MUX_GATE(rcan_clk, "rcan_clk", rcan_parent_names, + CRU_BASE_TYPE_RCPU, RCPU_CAN_CLK_RST, 8, 11, 4, 2, RT_BIT(1), RT_BIT(1), 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(rcan_bus_clk, "rcan_bus_clk", RT_NULL, + CRU_BASE_TYPE_RCPU, RCPU_CAN_CLK_RST, RT_BIT(2), RT_BIT(2), 0x0, 0); +/* RCPU2 */ +static const char *rpwm_parent_names[] = +{ + "pll1_aud_245p7", "pll1_aud_24p5" +}; +static SPACEMIT_CCU_DIV_MUX_GATE(rpwm0_clk, "rpwm0_clk", rpwm_parent_names, + CRU_BASE_TYPE_RCPU2, RCPU2_PWM0_CLK_RST, 8, 11, 4, 2, RT_BIT(1), RT_BIT(1), 0x0, 0); +static SPACEMIT_CCU_DIV_MUX_GATE(rpwm1_clk, "rpwm1_clk", rpwm_parent_names, + CRU_BASE_TYPE_RCPU2, RCPU2_PWM1_CLK_RST, 8, 11, 4, 2, RT_BIT(1), RT_BIT(1), 0x0, 0); +static SPACEMIT_CCU_DIV_MUX_GATE(rpwm2_clk, "rpwm2_clk", rpwm_parent_names, + CRU_BASE_TYPE_RCPU2, RCPU2_PWM2_CLK_RST, 8, 11, 4, 2, RT_BIT(1), RT_BIT(1), 0x0, 0); +static SPACEMIT_CCU_DIV_MUX_GATE(rpwm3_clk, "rpwm3_clk", rpwm_parent_names, + CRU_BASE_TYPE_RCPU2, RCPU2_PWM3_CLK_RST, 8, 11, 4, 2, RT_BIT(1), RT_BIT(1), 0x0, 0); +static SPACEMIT_CCU_DIV_MUX_GATE(rpwm4_clk, "rpwm4_clk", rpwm_parent_names, + CRU_BASE_TYPE_RCPU2, RCPU2_PWM4_CLK_RST, 8, 11, 4, 2, RT_BIT(1), RT_BIT(1), 0x0, 0); +static SPACEMIT_CCU_DIV_MUX_GATE(rpwm5_clk, "rpwm5_clk", rpwm_parent_names, + CRU_BASE_TYPE_RCPU2, RCPU2_PWM5_CLK_RST, 8, 11, 4, 2, RT_BIT(1), RT_BIT(1), 0x0, 0); +static SPACEMIT_CCU_DIV_MUX_GATE(rpwm6_clk, "rpwm6_clk", rpwm_parent_names, + CRU_BASE_TYPE_RCPU2, RCPU2_PWM6_CLK_RST, 8, 11, 4, 2, RT_BIT(1), RT_BIT(1), 0x0, 0); +static SPACEMIT_CCU_DIV_MUX_GATE(rpwm7_clk, "rpwm7_clk", rpwm_parent_names, + CRU_BASE_TYPE_RCPU2, RCPU2_PWM7_CLK_RST, 8, 11, 4, 2, RT_BIT(1), RT_BIT(1), 0x0, 0); +static SPACEMIT_CCU_DIV_MUX_GATE(rpwm8_clk, "rpwm8_clk", rpwm_parent_names, + CRU_BASE_TYPE_RCPU2, RCPU2_PWM8_CLK_RST, 8, 11, 4, 2, RT_BIT(1), RT_BIT(1), 0x0, 0); +static SPACEMIT_CCU_DIV_MUX_GATE(rpwm9_clk, "rpwm9_clk", rpwm_parent_names, + CRU_BASE_TYPE_RCPU2, RCPU2_PWM9_CLK_RST, 8, 11, 4, 2, RT_BIT(1), RT_BIT(1), 0x0, 0); + +static const char *ri2c_parent_names[] = +{ + "pll1_d40_61p44", "pll1_d96_25p6", "pll1_d192_12p8", "vctcxo_3" +}; +static SPACEMIT_CCU_DIV_MUX_GATE(ri2c0_clk, "ri2c0_clk", ri2c_parent_names, + CRU_BASE_TYPE_RCPU, RCPU_I2C0_CLK_RST, 8, 11, 4, 2, 0x6, 0x6, 0x0, 0); + +static const char *rssp0_parent_names[] = +{ + "pll1_d40_61p44", "pll1_d96_25p6", "pll1_d192_12p8", "vctcxo_3" +}; +static SPACEMIT_CCU_DIV_MUX_GATE(rssp0_clk, "rssp0_clk", rssp0_parent_names, + CRU_BASE_TYPE_RCPU, RCPU_SSP0_CLK_RST, 8, 11, 4, 2, 0x6, 0x6, 0x0, 0); +static SPACEMIT_CCU_GATE_NO_PARENT(rir_clk, "rir_clk", RT_NULL, + CRU_BASE_TYPE_RCPU, RCPU_IR_CLK_RST, RT_BIT(2), RT_BIT(2), 0x0, 0); +static const char *ruart0_parent_names[] = +{ + "pll1_aud_24p5", "pll1_aud_245p7", "vctcxo_24", "vctcxo_3" +}; +static SPACEMIT_CCU_DIV_MUX_GATE(ruart0_clk, "ruart0_clk", ruart0_parent_names, + CRU_BASE_TYPE_RCPU, RCPU_UART0_CLK_RST, 8, 11, 4, 2, 0x6, 0x6, 0x0, 0); +static const char *ruart1_parent_names[] = +{ + "pll1_aud_24p5", "pll1_aud_245p7", "vctcxo_24", "vctcxo_3" +}; +static SPACEMIT_CCU_DIV_MUX_GATE(ruart1_clk, "ruart1_clk", ruart1_parent_names, + CRU_BASE_TYPE_RCPU, RCPU_UART1_CLK_RST, 8, 11, 4, 2, 0x6, 0x6, 0x0, 0); + +static SPACEMIT_CCU_DIV_FLAG(audio_apb_clk, "audio_apb_clk", "audio_clk", + CRU_BASE_TYPE_AUDPMU, AUDPMU_AUDIO_BUS_CLK_CTRL, + 4, 3, CLK_DIVIDER_POWER_OF_TWO | CLK_DIVIDER_ALLOW_ZERO, 0); + +static SPACEMIT_CCU_DIV_FLAG(audio_axi_clk, "audio_axi_clk", "audio_clk", + CRU_BASE_TYPE_AUDPMU, AUDPMU_AUDIO_BUS_CLK_CTRL, + 0, 2, CLK_DIVIDER_POWER_OF_TWO | CLK_DIVIDER_ALLOW_ZERO, 0); + +static const rt_uint32_t bootup_enable_clk_table[] = +{ + CLK_PLL1_307P2, + CLK_PLL1_409P6, + CLK_PLL1_491, + CLK_PLL1_614, + CLK_PLL1_819, + CLK_PLL1_1228, + CLK_PLL1_245P76, + CLK_PLL1_51P2, + CLK_PLL1_51P2_AP, + CLK_PLL1_25P6, + CLK_PLL3_D1, + CLK_PLL3_D2, + CLK_PLL3_D3, + CLK_PLL2_D3, + CLK_APB, + CLK_PMUA_ACLK, + CLK_DMA, +}; + +static const rt_ubase_t bootup_set_rate_clk_table[] = +{ + CLK_PM_MN_SRC, 614400000, + CLK_PM_MN2_SRC, 600000000, +}; + +static struct rt_clk_cell *spacemit_k1x_ccu_cell[] = +{ + [CLK_PLL2] = &pll2.common.cell, + [CLK_PLL3] = &pll3.common.cell, + [CLK_PLL1_D2] = &pll1_d2.common.cell, + [CLK_PLL1_D3] = &pll1_d3.common.cell, + [CLK_PLL1_D4] = &pll1_d4.common.cell, + [CLK_PLL1_D5] = &pll1_d5.common.cell, + [CLK_PLL1_D6] = &pll1_d6.common.cell, + [CLK_PLL1_D7] = &pll1_d7.common.cell, + [CLK_PLL1_D8] = &pll1_d8.common.cell, + [CLK_PLL1_D11] = &pll1_d11_223p4.common.cell, + [CLK_PLL1_D13] = &pll1_d13_189.common.cell, + [CLK_PLL1_D23] = &pll1_d23_106p8.common.cell, + [CLK_PLL1_D64] = &pll1_d64_38p4.common.cell, + [CLK_PLL1_D10_AUD] = &pll1_aud_245p7.common.cell, + [CLK_PLL1_D100_AUD] = &pll1_aud_24p5.common.cell, + [CLK_PLL2_D1] = &pll2_d1.common.cell, + [CLK_PLL2_D2] = &pll2_d2.common.cell, + [CLK_PLL2_D3] = &pll2_d3.common.cell, + [CLK_PLL2_D4] = &pll2_d4.common.cell, + [CLK_PLL2_D5] = &pll2_d5.common.cell, + [CLK_PLL2_D6] = &pll2_d6.common.cell, + [CLK_PLL2_D7] = &pll2_d7.common.cell, + [CLK_PLL2_D8] = &pll2_d8.common.cell, + [CLK_PLL3_D1] = &pll3_d1.common.cell, + [CLK_PLL3_D2] = &pll3_d2.common.cell, + [CLK_PLL3_D3] = &pll3_d3.common.cell, + [CLK_PLL3_D4] = &pll3_d4.common.cell, + [CLK_PLL3_D5] = &pll3_d5.common.cell, + [CLK_PLL3_D6] = &pll3_d6.common.cell, + [CLK_PLL3_D7] = &pll3_d7.common.cell, + [CLK_PLL3_D8] = &pll3_d8.common.cell, + [CLK_PLL3_80] = &pll3_80.common.cell, + [CLK_PLL3_40] = &pll3_40.common.cell, + [CLK_PLL3_20] = &pll3_20.common.cell, + [CLK_PLL1_307P2] = &pll1_d8_307p2.common.cell, + [CLK_PLL1_76P8] = &pll1_d32_76p8.common.cell, + [CLK_PLL1_61P44] = &pll1_d40_61p44.common.cell, + [CLK_PLL1_153P6] = &pll1_d16_153p6.common.cell, + [CLK_PLL1_102P4] = &pll1_d24_102p4.common.cell, + [CLK_PLL1_51P2] = &pll1_d48_51p2.common.cell, + [CLK_PLL1_51P2_AP] = &pll1_d48_51p2_ap.common.cell, + [CLK_PLL1_57P6] = &pll1_m3d128_57p6.common.cell, + [CLK_PLL1_25P6] = &pll1_d96_25p6.common.cell, + [CLK_PLL1_12P8] = &pll1_d192_12p8.common.cell, + [CLK_PLL1_12P8_WDT] = &pll1_d192_12p8_wdt.common.cell, + [CLK_PLL1_6P4] = &pll1_d384_6p4.common.cell, + [CLK_PLL1_3P2] = &pll1_d768_3p2.common.cell, + [CLK_PLL1_1P6] = &pll1_d1536_1p6.common.cell, + [CLK_PLL1_0P8] = &pll1_d3072_0p8.common.cell, + [CLK_PLL1_351] = &pll1_d7_351p08.common.cell, + [CLK_PLL1_409P6] = &pll1_d6_409p6.common.cell, + [CLK_PLL1_204P8] = &pll1_d12_204p8.common.cell, + [CLK_PLL1_491] = &pll1_d5_491p52.common.cell, + [CLK_PLL1_245P76] = &pll1_d10_245p76.common.cell, + [CLK_PLL1_614] = &pll1_d4_614p4.common.cell, + [CLK_PLL1_47P26] = &pll1_d52_47p26.common.cell, + [CLK_PLL1_31P5] = &pll1_d78_31p5.common.cell, + [CLK_PLL1_819] = &pll1_d3_819p2.common.cell, + [CLK_PLL1_1228] = &pll1_d2_1228p8.common.cell, + [CLK_SLOW_UART1] = &slow_uart1_14p74.common.cell, + [CLK_SLOW_UART2] = &slow_uart2_48.common.cell, + [CLK_UART1] = &uart1_clk.common.cell, + [CLK_UART2] = &uart2_clk.common.cell, + [CLK_UART3] = &uart3_clk.common.cell, + [CLK_UART4] = &uart4_clk.common.cell, + [CLK_UART5] = &uart5_clk.common.cell, + [CLK_UART6] = &uart6_clk.common.cell, + [CLK_UART7] = &uart7_clk.common.cell, + [CLK_UART8] = &uart8_clk.common.cell, + [CLK_UART9] = &uart9_clk.common.cell, + [CLK_GPIO] = &gpio_clk.common.cell, + [CLK_PWM0] = &pwm0_clk.common.cell, + [CLK_PWM1] = &pwm1_clk.common.cell, + [CLK_PWM2] = &pwm2_clk.common.cell, + [CLK_PWM3] = &pwm3_clk.common.cell, + [CLK_PWM4] = &pwm4_clk.common.cell, + [CLK_PWM5] = &pwm5_clk.common.cell, + [CLK_PWM6] = &pwm6_clk.common.cell, + [CLK_PWM7] = &pwm7_clk.common.cell, + [CLK_PWM8] = &pwm8_clk.common.cell, + [CLK_PWM9] = &pwm9_clk.common.cell, + [CLK_PWM10] = &pwm10_clk.common.cell, + [CLK_PWM11] = &pwm11_clk.common.cell, + [CLK_PWM12] = &pwm12_clk.common.cell, + [CLK_PWM13] = &pwm13_clk.common.cell, + [CLK_PWM14] = &pwm14_clk.common.cell, + [CLK_PWM15] = &pwm15_clk.common.cell, + [CLK_PWM16] = &pwm16_clk.common.cell, + [CLK_PWM17] = &pwm17_clk.common.cell, + [CLK_PWM18] = &pwm18_clk.common.cell, + [CLK_PWM19] = &pwm19_clk.common.cell, + [CLK_SSP3] = &ssp3_clk.common.cell, + [CLK_RTC] = &rtc_clk.common.cell, + [CLK_TWSI0] = &twsi0_clk.common.cell, + [CLK_TWSI1] = &twsi1_clk.common.cell, + [CLK_TWSI2] = &twsi2_clk.common.cell, + [CLK_TWSI4] = &twsi4_clk.common.cell, + [CLK_TWSI5] = &twsi5_clk.common.cell, + [CLK_TWSI6] = &twsi6_clk.common.cell, + [CLK_TWSI7] = &twsi7_clk.common.cell, + [CLK_TWSI8] = &twsi8_clk.common.cell, + [CLK_TIMERS1] = &timers1_clk.common.cell, + [CLK_TIMERS2] = &timers2_clk.common.cell, + [CLK_AIB] = &aib_clk.common.cell, + [CLK_ONEWIRE] = &onewire_clk.common.cell, + [CLK_SSPA0] = &sspa0_clk.common.cell, + [CLK_SSPA1] = &sspa1_clk.common.cell, + [CLK_DRO] = &dro_clk.common.cell, + [CLK_IR] = &ir_clk.common.cell, + [CLK_TSEN] = &tsen_clk.common.cell, + [CLK_IPC_AP2AUD] = &ipc_ap2aud_clk.common.cell, + [CLK_CAN0] = &can0_clk.common.cell, + [CLK_CAN0_BUS] = &can0_bus_clk.common.cell, + [CLK_WDT] = &wdt_clk.common.cell, + [CLK_RIPC] = &ripc_clk.common.cell, + [CLK_JPG] = &jpg_clk.common.cell, + [CLK_JPF_4KAFBC] = &jpg_4kafbc_clk.common.cell, + [CLK_JPF_2KAFBC] = &jpg_2kafbc_clk.common.cell, + [CLK_CCIC2PHY] = &ccic2phy_clk.common.cell, + [CLK_CCIC3PHY] = &ccic3phy_clk.common.cell, + [CLK_CSI] = &csi_clk.common.cell, + [CLK_CAMM0] = &camm0_clk.common.cell, + [CLK_CAMM1] = &camm1_clk.common.cell, + [CLK_CAMM2] = &camm2_clk.common.cell, + [CLK_ISP_CPP] = &isp_cpp_clk.common.cell, + [CLK_ISP_BUS] = &isp_bus_clk.common.cell, + [CLK_ISP] = &isp_clk.common.cell, + [CLK_DPU_MCLK] = &dpu_mclk.common.cell, + [CLK_DPU_ESC] = &dpu_esc_clk.common.cell, + [CLK_DPU_BIT] = &dpu_bit_clk.common.cell, + [CLK_DPU_PXCLK] = &dpu_pxclk.common.cell, + [CLK_DPU_HCLK] = &dpu_hclk.common.cell, + [CLK_DPU_SPI] = &dpu_spi_clk.common.cell, + [CLK_DPU_SPI_HBUS] = &dpu_spi_hbus_clk.common.cell, + [CLK_DPU_SPIBUS] = &dpu_spi_bus_clk.common.cell, + [CLK_SPU_SPI_ACLK] = &dpu_spi_aclk.common.cell, + [CLK_V2D] = &v2d_clk.common.cell, + [CLK_CCIC_4X] = &ccic_4x_clk.common.cell, + [CLK_CCIC1PHY] = &ccic1phy_clk.common.cell, + [CLK_SDH_AXI] = &sdh_axi_aclk.common.cell, + [CLK_SDH0] = &sdh0_clk.common.cell, + [CLK_SDH1] = &sdh1_clk.common.cell, + [CLK_SDH2] = &sdh2_clk.common.cell, + [CLK_USB_P1] = &usb_p1_aclk.common.cell, + [CLK_USB_AXI] = &usb_axi_clk.common.cell, + [CLK_USB30] = &usb30_clk.common.cell, + [CLK_QSPI] = &qspi_clk.common.cell, + [CLK_QSPI_BUS] = &qspi_bus_clk.common.cell, + [CLK_DMA] = &dma_clk.common.cell, + [CLK_AES] = &aes_clk.common.cell, + [CLK_VPU] = &vpu_clk.common.cell, + [CLK_GPU] = &gpu_clk.common.cell, + [CLK_EMMC] = &emmc_clk.common.cell, + [CLK_EMMC_X] = &emmc_x_clk.common.cell, + [CLK_AUDIO] = &audio_clk.common.cell, + [CLK_HDMI] = &hdmi_mclk.common.cell, + [CLK_CCI550] = &cci550_clk.common.cell, + [CLK_PMUA_ACLK] = &pmua_aclk.common.cell, + [CLK_CPU_C0_HI] = &cpu_c0_hi_clk.common.cell, + [CLK_CPU_C0_CORE] = &cpu_c0_core_clk.common.cell, + [CLK_CPU_C0_ACE] = &cpu_c0_ace_clk.common.cell, + [CLK_CPU_C0_TCM] = &cpu_c0_tcm_clk.common.cell, + [CLK_CPU_C1_HI] = &cpu_c1_hi_clk.common.cell, + [CLK_CPU_C1_CORE] = &cpu_c1_pclk.common.cell, + [CLK_CPU_C1_ACE] = &cpu_c1_ace_clk.common.cell, + [CLK_PCIE0] = &pcie0_clk.common.cell, + [CLK_PCIE1] = &pcie1_clk.common.cell, + [CLK_PCIE2] = &pcie2_clk.common.cell, + [CLK_EMAC0_BUS] = &emac0_bus_clk.common.cell, + [CLK_EMAC0_PTP] = &emac0_ptp_clk.common.cell, + [CLK_EMAC1_BUS] = &emac1_bus_clk.common.cell, + [CLK_EMAC1_PTP] = &emac1_ptp_clk.common.cell, + [CLK_SEC_UART1] = &uart1_sec_clk.common.cell, + [CLK_SEC_SSP2] = &ssp2_sec_clk.common.cell, + [CLK_SEC_TWSI3] = &twsi3_sec_clk.common.cell, + [CLK_SEC_RTC] = &rtc_sec_clk.common.cell, + [CLK_SEC_TIMERS0] = &timers0_sec_clk.common.cell, + [CLK_SEC_KPC] = &kpc_sec_clk.common.cell, + [CLK_SEC_GPIO] = &gpio_sec_clk.common.cell, + [CLK_APB] = &apb_clk.common.cell, + [CLK_SLOW_UART] = &slow_uart.common.cell, + [CLK_I2S_SYSCLK] = &i2s_sysclk.common.cell, + [CLK_I2S_BCLK] = &i2s_bclk.common.cell, + [CLK_RCPU_HDMIAUDIO] = &rhdmi_audio_clk.common.cell, + [CLK_RCPU_CAN] = &rcan_clk.common.cell, + [CLK_RCPU_CAN_BUS] = &rcan_bus_clk.common.cell, + [CLK_RCPU_I2C0] = &ri2c0_clk.common.cell, + [CLK_RCPU_SSP0] = &rssp0_clk.common.cell, + [CLK_RCPU_IR] = &rir_clk.common.cell, + [CLK_RCPU_UART0] = &ruart0_clk.common.cell, + [CLK_RCPU_UART1] = &ruart1_clk.common.cell, + [CLK_DPLL1] = &dpll1.common.cell, + [CLK_DPLL2] = &dpll2.common.cell, + [CLK_DFC_LVL0] = &dfc_lvl0.common.cell, + [CLK_DFC_LVL1] = &dfc_lvl1.common.cell, + [CLK_DFC_LVL2] = &dfc_lvl2.common.cell, + [CLK_DFC_LVL3] = &dfc_lvl3.common.cell, + [CLK_DFC_LVL4] = &dfc_lvl4.common.cell, + [CLK_DFC_LVL5] = &dfc_lvl5.common.cell, + [CLK_DFC_LVL6] = &dfc_lvl6.common.cell, + [CLK_DFC_LVL7] = &dfc_lvl7.common.cell, + [CLK_DDR] = &ddr.common.cell, + [CLK_RCPU2_PWM0] = &rpwm0_clk.common.cell, + [CLK_RCPU2_PWM1] = &rpwm1_clk.common.cell, + [CLK_RCPU2_PWM2] = &rpwm2_clk.common.cell, + [CLK_RCPU2_PWM3] = &rpwm3_clk.common.cell, + [CLK_RCPU2_PWM4] = &rpwm4_clk.common.cell, + [CLK_RCPU2_PWM5] = &rpwm5_clk.common.cell, + [CLK_RCPU2_PWM6] = &rpwm6_clk.common.cell, + [CLK_RCPU2_PWM7] = &rpwm7_clk.common.cell, + [CLK_RCPU2_PWM8] = &rpwm8_clk.common.cell, + [CLK_RCPU2_PWM9] = &rpwm9_clk.common.cell, + [CLK_AUDIO_APB] = &audio_apb_clk.common.cell, + [CLK_AUDIO_AXI] = &audio_axi_clk.common.cell, + [CLK_PM_MN_SRC] = &mn_src_clk.common.cell, + [CLK_PM_MN] = &mn_clk.common.cell, + [CLK_PM_MN2_SRC] = &mn2_src_clk.common.cell, + [CLK_PM_MN2] = &mn2_clk.common.cell, +}; + +static rt_err_t spacemit_k1x_ccu_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + int reg_count; + struct ccu_common *common; + struct rt_clk *clk; + struct rt_clk_cell *cell; + struct rt_device *dev = &pdev->parent; + struct k1x_clk *kclk = rt_calloc(1, sizeof(*kclk)); + + if (!kclk) + { + return -RT_ENOMEM; + } + + reg_count = rt_dm_dev_get_address_count(dev); + + for (int i = 0; i < reg_count; ++i) + { + kclk->mmio[i] = rt_dm_dev_iomap(dev, i); + + if (!kclk->mmio[i]) + { + err = -RT_EIO; + goto _fail; + } + } + + for (int i = 0; i < RT_ARRAY_SIZE(spacemit_k1x_ccu_cell); ++i) + { + if (!(cell = spacemit_k1x_ccu_cell[i])) + { + continue; + } + + common = cell_to_ccu_common(cell); + + common->lock = &k1_cru_lock; + + if (common->base_type < reg_count) + { + common->base = kclk->mmio[common->base_type]; + } + else + { + common->base = kclk->apbc_base; + } + + if (common->is_pll) + { + struct ccu_pll *pll = rt_container_of(common, struct ccu_pll, common); + + pll->pll.lock_base = kclk->mpmu_base; + } + } + + kclk->parent.dev = dev; + kclk->parent.cells = spacemit_k1x_ccu_cell; + kclk->parent.cells_nr = RT_ARRAY_SIZE(spacemit_k1x_ccu_cell); + + if ((err = rt_clk_register(&kclk->parent))) + { + goto _fail; + } + + /* Enable some clocks */ + for (int i = 0; i < RT_ARRAY_SIZE(bootup_enable_clk_table); ++i) + { + cell = spacemit_k1x_ccu_cell[bootup_enable_clk_table[i]]; + + if (cell && (clk = rt_clk_cell_get_clk(cell, RT_NULL))) + { + rt_clk_prepare_enable(clk); + } + } + + /* Init some clocks' rate */ + for (int i = 0; i < RT_ARRAY_SIZE(bootup_set_rate_clk_table); ++i) + { + cell = spacemit_k1x_ccu_cell[bootup_set_rate_clk_table[i++]]; + + if (cell && (clk = rt_clk_cell_get_clk(cell, RT_NULL))) + { + rt_clk_set_rate(clk, bootup_set_rate_clk_table[i]); + } + } + + return RT_EOK; + +_fail: + for (int i = 0; i < CRU_BASE_TYPE_AUDC; ++i) + { + if (kclk->mmio[i]) + { + rt_iounmap(kclk->mmio[i]); + } + } + + rt_free(kclk); + + return err; +} + +static const struct rt_ofw_node_id spacemit_k1x_ccu_ofw_ids[] = +{ + { .compatible = "spacemit,k1x-clock" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_k1x_ccu_driver = +{ + .name = "clk-spacemit-k1x", + .ids = spacemit_k1x_ccu_ofw_ids, + + .probe = spacemit_k1x_ccu_probe, +}; + +static int spacemit_k1x_ccu_register(void) +{ + rt_platform_driver_register(&spacemit_k1x_ccu_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(spacemit_k1x_ccu_register); diff --git a/bsp/spacemit/dm/clk/ccu.h b/bsp/spacemit/dm/clk/ccu.h new file mode 100644 index 000000000000..6aba95c70eb1 --- /dev/null +++ b/bsp/spacemit/dm/clk/ccu.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __CCU_H__ +#define __CCU_H__ + +#include +#include + +#define CLK_DIVIDER_POWER_OF_TWO RT_BIT(1) +#define CLK_DIVIDER_ALLOW_ZERO RT_BIT(2) + +enum +{ + CLK_DIV_TYPE_1REG_NOFC_V1 = 0, + CLK_DIV_TYPE_1REG_FC_V2, + CLK_DIV_TYPE_2REG_NOFC_V3, + CLK_DIV_TYPE_2REG_FC_V4, + CLK_DIV_TYPE_1REG_FC_DIV_V5, + CLK_DIV_TYPE_1REG_FC_MUX_V6, +}; + +struct ccu_common +{ + void *base; + + rt_bool_t is_pll; + rt_uint32_t base_type; + + rt_uint32_t reg_type; + rt_uint32_t reg_ctrl; + rt_uint32_t reg_sel; + rt_uint32_t reg_xtc; + rt_uint32_t fc; + + struct rt_spinlock *lock; + + rt_ubase_t rate; + + struct rt_clk_cell cell; +}; + +#define cell_to_ccu_common(cell) rt_container_of(cell, struct ccu_common, cell); + +#endif /* __CCU_H__ */ diff --git a/bsp/spacemit/dm/clk/ccu_ddn.c b/bsp/spacemit/dm/clk/ccu_ddn.c new file mode 100644 index 000000000000..1ff0b0c38bae --- /dev/null +++ b/bsp/spacemit/dm/clk/ccu_ddn.c @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include "ccu_ddn.h" + +#define DBG_TAG "clk.ccu.ddn" +#define DBG_LVL DBG_INFO +#include + +/* + * It is M/N clock + * + * Fout from synthesizer can be given from two equations: + * numerator/denominator = Fin / (Fout * factor) + */ + +static void ccu_ddn_disable(struct rt_clk_cell *cell) +{ + rt_uint32_t reg; + rt_ubase_t level; + struct ccu_ddn *ddn = cell_to_ccu_ddn(cell); + struct ccu_common *common = &ddn->common; + + if (!ddn->gate) + { + return; + } + + level = rt_spin_lock_irqsave(common->lock); + + reg = HWREG32(common->base + common->reg_sel); + HWREG32(common->base + common->reg_sel) = reg & ~ddn->gate; + + rt_spin_unlock_irqrestore(common->lock, level); +} + +static rt_err_t ccu_ddn_enable(struct rt_clk_cell *cell) +{ + rt_uint32_t reg; + rt_ubase_t level; + struct ccu_ddn *ddn = cell_to_ccu_ddn(cell); + struct ccu_common *common = &ddn->common; + + if (!ddn->gate) + { + return RT_EOK; + } + + level = rt_spin_lock_irqsave(common->lock); + + reg = HWREG32(common->base + common->reg_sel); + HWREG32(common->base + common->reg_sel) = reg | ddn->gate; + + rt_spin_unlock_irqrestore(common->lock, level); + + return RT_EOK; +} + +static rt_bool_t ccu_ddn_is_enabled(struct rt_clk_cell *cell) +{ + struct ccu_ddn *ddn = cell_to_ccu_ddn(cell); + struct ccu_common *common = &ddn->common; + + if (!ddn->gate) + { + return RT_TRUE; + } + + return HWREG32(common->base + common->reg_sel) & ddn->gate; +} + +static rt_ubase_t ccu_ddn_recalc_rate(struct rt_clk_cell *cell, rt_ubase_t parent_rate) +{ + rt_ubase_t rate; + rt_uint32_t val, num, den; + struct ccu_ddn *ddn = cell_to_ccu_ddn(cell); + struct ccu_ddn_config *params = &ddn->ddn; + + val = HWREG32(ddn->common.base + ddn->common.reg_ctrl); + + /* Calculate numerator */ + num = (val >> params->info->num_shift) & params->info->num_mask; + + /* Calculate denominator */ + den = (val >> params->info->den_shift) & params->info->den_mask; + + if (!den) + { + return 0; + } + + rate = (((parent_rate / 10000) * den) / (num * params->info->factor)) * 10000; + + return rate; +} + +static rt_base_t ccu_ddn_round_rate(struct rt_clk_cell *cell, rt_ubase_t drate, rt_ubase_t *prate) +{ + int i; + rt_ubase_t result, rate = 0, prev_rate; + struct ccu_ddn *ddn = cell_to_ccu_ddn(cell); + struct ccu_ddn_config *params = &ddn->ddn; + + for (i = 0; i < params->tbl_size; ++i) + { + prev_rate = rate; + rate = (((*prate / 10000) * params->tbl[i].den) / + (params->tbl[i].num * params->info->factor)) * 10000; + + if (rate > drate) + { + break; + } + } + + if (i == 0 || i == params->tbl_size) + { + result = rate; + } + else + { + if (drate - prev_rate > rate - drate) + { + result = rate; + } + else + { + result = prev_rate; + } + } + + return result; +} + +/* Configures new clock rate */ +static rt_err_t ccu_ddn_set_rate(struct rt_clk_cell *cell, rt_ubase_t drate, rt_ubase_t prate) +{ + int i; + rt_ubase_t val, rate = 0, level; + struct ccu_ddn *ddn = cell_to_ccu_ddn(cell); + struct ccu_common *common = &ddn->common; + struct ccu_ddn_config *params = &ddn->ddn; + + for (i = 0; i < params->tbl_size; ++i) + { + rate = (((prate / 10000) * params->tbl[i].den) / + (params->tbl[i].num * params->info->factor)) * 10000; + + if (rate > drate) + { + break; + } + } + + if (i > 0) + { + --i; + } + + if (ddn->common.lock) + { + level = rt_spin_lock_irqsave(common->lock); + } + + val = HWREG32(ddn->common.base + ddn->common.reg_ctrl); + + val &= ~(params->info->num_mask << params->info->num_shift); + val |= (params->tbl[i].num & params->info->num_mask) << params->info->num_shift; + + val &= ~(params->info->den_mask << params->info->den_shift); + val |= (params->tbl[i].den & params->info->den_mask) << params->info->den_shift; + + HWREG32(ddn->common.base + ddn->common.reg_ctrl) = val; + + if (ddn->common.lock) + { + rt_spin_unlock_irqrestore(common->lock, level); + } + + return RT_EOK; +} + +const struct rt_clk_ops ccu_ddn_ops = +{ + .disable = ccu_ddn_disable, + .enable = ccu_ddn_enable, + .is_enabled = ccu_ddn_is_enabled, + .recalc_rate = ccu_ddn_recalc_rate, + .round_rate = ccu_ddn_round_rate, + .set_rate = ccu_ddn_set_rate, +}; diff --git a/bsp/spacemit/dm/clk/ccu_ddn.h b/bsp/spacemit/dm/clk/ccu_ddn.h new file mode 100644 index 000000000000..c0f5a7f755b7 --- /dev/null +++ b/bsp/spacemit/dm/clk/ccu_ddn.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __CCU_DDN_H__ +#define __CCU_DDN_H__ + +#include "ccu.h" + +struct ccu_ddn_tbl +{ + rt_uint32_t num; + rt_uint32_t den; +}; + +struct ccu_ddn_info +{ + rt_uint32_t factor; + rt_uint32_t num_mask; + rt_uint32_t den_mask; + rt_uint32_t num_shift; + rt_uint32_t den_shift; +}; + +struct ccu_ddn_config +{ + rt_uint32_t tbl_size; + struct ccu_ddn_tbl *tbl; + struct ccu_ddn_info *info; +}; + +struct ccu_ddn +{ + struct ccu_common common; + struct ccu_ddn_config ddn; + rt_uint32_t gate; +}; + +#define PLL_DDN_TBL(_num, _den) \ +{ \ + .num = (_num), \ + .den = (_den), \ +} + +#define _SPACEMIT_CCU_DDN_CONFIG(_info, _table, _size) \ +{ \ + .info = (struct ccu_ddn_info *)_info, \ + .tbl = (struct ccu_ddn_tbl *)_table, \ + .tbl_size = _size, \ +} + +#define SPACEMIT_CCU_DDN(_struct, _name, _parent, _info, _table, \ + _size, _base_type, _reg_ctrl, _flags) \ +struct ccu_ddn _struct = \ +{ \ + .ddn = _SPACEMIT_CCU_DDN_CONFIG(_info, _table, _size), \ + .common = \ + { \ + .reg_ctrl = _reg_ctrl, \ + .base_type = _base_type, \ + .cell.name = _name, \ + .cell.parent_name = _parent, \ + .cell.parents_nr = 1, \ + .cell.ops = &ccu_ddn_ops, \ + .cell.flags = _flags, \ + }, \ +} + +#define SPACEMIT_CCU_DDN_GATE(_struct, _name, _parent, _info, _table, _size, \ + _base_type, _reg_ddn, _reg_gate, _gate_mask, _flags) \ +struct ccu_ddn _struct = \ +{ \ + .gate = _gate_mask, \ + .ddn = _SPACEMIT_CCU_DDN_CONFIG(_info, _table, _size), \ + .common = \ + { \ + .reg_ctrl = _reg_ddn, \ + .reg_sel = _reg_gate, \ + .base_type = _base_type, \ + .cell.name = _name, \ + .cell.parent_name = _parent, \ + .cell.parents_nr = 1, \ + .cell.ops = &ccu_ddn_ops, \ + .cell.flags = _flags, \ + } \ +} + +extern const struct rt_clk_ops ccu_ddn_ops; + +rt_inline struct ccu_ddn *cell_to_ccu_ddn(struct rt_clk_cell *cell) +{ + struct ccu_common *common = cell_to_ccu_common(cell); + + return rt_container_of(common, struct ccu_ddn, common); +} + +#endif /* __CCU_DDN_H__ */ diff --git a/bsp/spacemit/dm/clk/ccu_ddr.c b/bsp/spacemit/dm/clk/ccu_ddr.c new file mode 100644 index 000000000000..4401fa5eb0f4 --- /dev/null +++ b/bsp/spacemit/dm/clk/ccu_ddr.c @@ -0,0 +1,298 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include "ccu_ddr.h" + +#define DBG_TAG "clk.ccu.ddr" +#define DBG_LVL DBG_INFO +#include + +#define PMU_AP_IMR 0x098 +#define AP_DCLK_FC_DONE_INT_MSK RT_BIT(15) +#define DCLK_FC_DONE_INT_MSK RT_BIT(4) + +#define PMU_AP_ISR 0x0a0 +#define AP_DCLK_FC_DONE_INT_STS RT_BIT(15) +#define DCLK_FC_DONE_INT_STS RT_BIT(4) +#define AP_FC_STS RT_BIT(1) + +#define DFC_AP 0x180 +#define DFC_FREQ_LV 0x1 +#define DFC_REQ RT_BIT(0) + +#define DFC_STATUS 0x188 +#define DFC_CAUSE_SHIFT 0x7 +#define DFC_STS RT_BIT(0) + +/* Enable/disable ddr frequency change done interrupt */ +static void ccu_ddr_enable_dfc_int(struct ccu_common *common, rt_bool_t enable) +{ + rt_uint32_t val; + rt_ubase_t level; + + level = rt_spin_lock_irqsave(common->lock); + + val = HWREG32(common->base + PMU_AP_IMR); + if (enable) + { + val |= AP_DCLK_FC_DONE_INT_MSK; + } + else + { + val &= ~AP_DCLK_FC_DONE_INT_MSK; + } + HWREG32(common->base + PMU_AP_IMR) = val; + + rt_spin_unlock_irqrestore(common->lock, level); +} + +/* clear ddr frequency change done interrupt status*/ +static void ccu_ddr_clear_dfc_int_status(struct ccu_common *common) +{ + rt_uint32_t val; + rt_ubase_t level; + + level = rt_spin_lock_irqsave(common->lock); + + val = HWREG32(common->base + PMU_AP_ISR); + val &= ~(AP_DCLK_FC_DONE_INT_STS | AP_FC_STS); + HWREG32(common->base + PMU_AP_ISR) = val; + + rt_spin_unlock_irqrestore(common->lock, level); +} + +static rt_err_t ccu_ddr_wait_freq_change_done(struct ccu_common *common) +{ + int timeout = 100; + + while (--timeout) + { + rt_hw_us_delay(10); + + if (HWREG32(common->base + PMU_AP_ISR) & AP_DCLK_FC_DONE_INT_STS) + { + break; + } + } + + if (!timeout) + { + LOG_E("%s:%s timeout, can not wait dfc done interrupt", __func__, common->cell.name); + return -RT_EBUSY; + } + + return RT_EOK; +} + +static rt_err_t ccu_ddr_freq_chg(struct ccu_common *common, + struct ccu_mux_config *mux, rt_uint8_t level_no) +{ + rt_ubase_t level; + rt_uint32_t reg, timeout; + + if (level_no > MAX_FREQ_LV) + { + LOG_E("%s:%s invalid %d freq level", __func__, common->cell.name, level_no); + return -RT_EINVAL; + } + + /* Check if dfc in progress */ + timeout = 1000; + while (--timeout) + { + if (!(HWREG32(common->base + DFC_STATUS) & DFC_STS)) + { + break; + } + rt_hw_us_delay(10); + } + + if (!timeout) + { + LOG_E("%s:%s another dfc is in pregress. status: %#x", + __func__, common->cell.name, HWREG32(common->base + DFC_STATUS)); + return -RT_EBUSY; + } + + level = rt_spin_lock_irqsave(common->lock); + + reg = HWREG32(common->base + common->reg_sel); + reg &= ~RT_GENMASK(mux->width + mux->shift - 1, mux->shift); + HWREG32(common->base + common->reg_sel) = reg | (level_no << mux->shift) | common->fc; + + rt_spin_unlock_irqrestore(common->lock, level); + + timeout = 1000; + while (--timeout) + { + rt_hw_us_delay(10); + + if (!(HWREG32(common->base + DFC_STATUS) & DFC_STS)) + { + break; + } + } + + if (!timeout) + { + LOG_E("%s dfc error! status: %#x", common->cell.name, HWREG32(common->base + DFC_STATUS)); + return -RT_EBUSY; + } + + return RT_EOK; +} + +static rt_ubase_t ccu_ddr_calc_best_rate(struct rt_clk_cell *cell, + rt_ubase_t rate, rt_uint32_t *mux_val) +{ + rt_ubase_t parent_rate = 0, best_rate = 0; + struct rt_clk_cell *parent; + + for (int i = 0; i < cell->parents_nr; ++i) + { + parent = rt_clk_cell_get_parent_by_index(cell, i); + + if (!parent) + { + continue; + } + + parent_rate = rt_clk_cell_get_rate(parent); + + if (rt_abs(parent_rate - rate) < rt_abs(best_rate - rate)) + { + best_rate = parent_rate; + *mux_val = i; + } + } + + return best_rate; +} + +static rt_ubase_t ccu_ddr_recalc_rate(struct rt_clk_cell *cell, rt_ubase_t parent_rate) +{ + return parent_rate; +} + +static rt_base_t ccu_ddr_round_rate(struct rt_clk_cell *cell, rt_ubase_t drate, rt_ubase_t *prate) +{ + return drate; +} + +static rt_err_t ccu_ddr_set_rate(struct rt_clk_cell *cell, rt_ubase_t rate, rt_ubase_t parent_rate) +{ + rt_uint32_t cur_mux, mux_val = 0, reg = 0; + struct ccu_ddr *ddr = cell_to_ccu_ddr(cell); + struct ccu_common *common = &ddr->common; + struct ccu_mux_config *mux = ddr->mux ? : RT_NULL; + + if (!mux) + { + return RT_EOK; + } + + ccu_ddr_calc_best_rate(cell, rate, &mux_val); + + reg = HWREG32(common->base + common->reg_sel); + + if (mux) + { + cur_mux = reg >> mux->shift; + cur_mux &= (1 << mux->width) - 1; + + if (cur_mux != mux_val) + { + rt_clk_cell_set_parent(cell, rt_clk_cell_get_parent_by_index(cell, mux_val)); + } + } + + return RT_EOK; +} + +static rt_err_t ccu_ddr_set_parent(struct rt_clk_cell *cell, rt_uint8_t idx) +{ + rt_err_t err; + struct ccu_ddr *ddr = cell_to_ccu_ddr(cell); + struct ccu_common *common = &ddr->common; + struct ccu_mux_config *mux = ddr->mux; + + if (!mux) + { + return RT_EOK; + } + + if (mux->table) + { + idx = mux->table[idx]; + } + + /* Request change begin */ + ccu_ddr_enable_dfc_int(common, RT_TRUE); + + /* Change parent*/ + if ((err = ccu_ddr_freq_chg(common, mux, idx))) + { + LOG_E("%s:%s ddr_freq_chg fail", __func__, common->cell.name); + return err; + } + + /* Wait for frequency change done */ + if ((err = ccu_ddr_wait_freq_change_done(common))) + { + LOG_E("%s: %s timeout", __func__, "wait_freq_change_done"); + return err; + } + + ccu_ddr_clear_dfc_int_status(common); + ccu_ddr_enable_dfc_int(common, RT_FALSE); + + return RT_EOK; +} + +static rt_uint8_t ccu_ddr_get_parent(struct rt_clk_cell *cell) +{ + rt_uint32_t reg; + rt_uint8_t parent; + struct ccu_ddr *ddr = cell_to_ccu_ddr(cell); + struct ccu_common *common = &ddr->common; + struct ccu_mux_config *mux = ddr->mux; + + if (!mux) + { + return 0; + } + + reg = HWREG32(common->base + common->reg_sel); + + parent = reg >> mux->shift; + parent &= (1 << mux->width) - 1; + + if (mux->table) + { + for (int i = 0; i < common->cell.parents_nr; ++i) + { + if (mux->table[i] == parent) + { + return i; + } + } + } + + return parent; +} + +const struct rt_clk_ops ccu_ddr_ops = +{ + .recalc_rate = ccu_ddr_recalc_rate, + .round_rate = ccu_ddr_round_rate, + .set_rate = ccu_ddr_set_rate, + .set_parent = ccu_ddr_set_parent, + .get_parent = ccu_ddr_get_parent, +}; diff --git a/bsp/spacemit/dm/clk/ccu_ddr.h b/bsp/spacemit/dm/clk/ccu_ddr.h new file mode 100644 index 000000000000..f11dce6de44f --- /dev/null +++ b/bsp/spacemit/dm/clk/ccu_ddr.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __CCU_DDR_H__ +#define __CCU_DDR_H__ + +#include "ccu.h" +#include "ccu_mix.h" + +struct ccu_ddr +{ + struct ccu_common common; + struct ccu_mux_config *mux; +}; + +#define MAX_FREQ_LV 7 /* level 0~7 */ + +#define SPACEMIT_CCU_DDR_FC(_struct, _name, _parents, _base_type, \ + _reg, _fc, _shift, _width, _flags) \ +struct ccu_ddr _struct = \ +{ \ + .mux = CCU_MUX_INIT(_shift, _width, RT_NULL), \ + .common = \ + { \ + .reg_sel = _reg, \ + .fc = _fc, \ + .base_type = _base_type, \ + .cell.name = _name, \ + .cell.parent_names = _parents, \ + .cell.parents_nr = RT_ARRAY_SIZE(_parents), \ + .cell.ops = &ccu_ddr_ops, \ + .cell.flags = _flags, \ + }, \ +} + +extern const struct rt_clk_ops ccu_ddr_ops; + +rt_inline struct ccu_ddr *cell_to_ccu_ddr(struct rt_clk_cell *cell) +{ + struct ccu_common *common = cell_to_ccu_common(cell); + + return rt_container_of(common, struct ccu_ddr, common); +} + +#endif /* __CCU_DDR_H__ */ diff --git a/bsp/spacemit/dm/clk/ccu_dpll.c b/bsp/spacemit/dm/clk/ccu_dpll.c new file mode 100644 index 000000000000..80cc0ba74060 --- /dev/null +++ b/bsp/spacemit/dm/clk/ccu_dpll.c @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include "ccu_dpll.h" + +#define DBG_TAG "clk.ccu.dpll" +#define DBG_LVL DBG_INFO +#include + +#define DPLL_MIN_FREQ 1700000000 +#define DPLL_MAX_FREQ 3400000000 + +#define pll_readl(reg) HWREG32(reg) +#define pll_readl_pll_swcr1(p) pll_readl(p.base + p.reg_ctrl) +#define pll_readl_pll_swcr2(p) pll_readl(p.base + p.reg_sel) + +#define pll_writel(val, reg) HWREG32(reg) = val +#define pll_writel_pll_swcr1(val, p) pll_writel(val, p.base + p.reg_ctrl) +#define pll_writel_pll_swcr2(val, p) pll_writel(val, p.base + p.reg_sel) + +/* Unified dpllx_swcr1 for dpll1~2 */ +union dpllx_swcr1 +{ + struct + { + rt_uint32_t reg0:8; + rt_uint32_t reg1:8; + rt_uint32_t reg2:8; + rt_uint32_t reg3:8; + } b; + rt_uint32_t v; +}; + +/* Unified dpllx_swcr2 for dpll1~2 */ +union dpllx_swcr2 +{ + struct + { + rt_uint32_t reg4:8; + rt_uint32_t reg5:8; + rt_uint32_t reg6:8; + rt_uint32_t reg7:8; + } b; + rt_uint32_t v; +}; + +/* Frequency unit Mhz, return pll vco freq */ +static rt_ubase_t __get_vco_freq_raw(struct rt_clk_cell *cell) +{ + rt_uint32_t reg0, reg1, reg2, reg3, reg4, reg5, reg6, reg7, size; + union dpllx_swcr1 swcr1; + union dpllx_swcr2 swcr2; + struct ccu_dpll_rate_tbl *freq_pll_regs_table; + struct ccu_dpll *p = cell_to_ccu_dpll(cell); + + swcr1.v = pll_readl_pll_swcr1(p->common); + swcr2.v = pll_readl_pll_swcr2(p->common); + + reg0 = swcr1.b.reg0; + reg1 = swcr1.b.reg1; + reg2 = swcr1.b.reg2; + reg3 = swcr1.b.reg3; + reg4 = swcr2.b.reg4; + reg5 = swcr2.b.reg5; + reg6 = swcr2.b.reg6; + reg7 = swcr2.b.reg7; + + freq_pll_regs_table = p->dpll.rate_tbl; + size = p->dpll.tbl_size; + + for (int i = 0; i < size; ++i) + { + struct ccu_dpll_rate_tbl *item = &freq_pll_regs_table[i]; + + if (item->reg0 == reg0 && + item->reg1 == reg1 && + item->reg2 == reg2 && + item->reg3 == reg3 && + item->reg4 == reg4 && + item->reg5 == reg5 && + item->reg6 == reg6 && + item->reg7 == reg7) + { + return item->rate; + } + } + + LOG_E("Unknown rate for clock %s", cell->name); + + return 0; +} + +static rt_ubase_t ccu_dpll_recalc_rate(struct rt_clk_cell *cell, rt_ubase_t parent_rate) +{ + return __get_vco_freq_raw(cell); +} + +static rt_base_t ccu_dpll_round_rate(struct rt_clk_cell *cell, rt_ubase_t rate, rt_ubase_t *prate) +{ + rt_ubase_t max_rate = 0; + struct ccu_dpll *p = cell_to_ccu_dpll(cell); + struct ccu_dpll_config *params = &p->dpll; + + if (rate > DPLL_MAX_FREQ || rate < DPLL_MIN_FREQ) + { + LOG_E("%s %lu rate out of range", cell->name, rate); + return -RT_EINVAL; + } + + if (params->rate_tbl) + { + for (int i = 0; i < params->tbl_size; ++i) + { + struct ccu_dpll_rate_tbl *item = ¶ms->rate_tbl[i]; + + if (item->rate <= rate) + { + if (max_rate < item->rate) + { + max_rate = item->rate; + } + } + } + } + else + { + LOG_E("%s don't find freq table for pll", cell->name); + } + + return max_rate; +} + +const struct rt_clk_ops ccu_dpll_ops = +{ + .recalc_rate = ccu_dpll_recalc_rate, + .round_rate = ccu_dpll_round_rate, +}; diff --git a/bsp/spacemit/dm/clk/ccu_dpll.h b/bsp/spacemit/dm/clk/ccu_dpll.h new file mode 100644 index 000000000000..7fc6014e5880 --- /dev/null +++ b/bsp/spacemit/dm/clk/ccu_dpll.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __CCU_DPLL_H__ +#define __CCU_DPLL_H__ + +#include "ccu.h" + +struct ccu_dpll_rate_tbl +{ + rt_uint64_t rate; + rt_uint32_t reg0; + rt_uint32_t reg1; + rt_uint32_t reg2; + rt_uint32_t reg3; + rt_uint32_t reg4; + rt_uint32_t reg5; + rt_uint32_t reg6; + rt_uint32_t reg7; +}; + +struct ccu_dpll_config +{ + rt_uint32_t tbl_size; + struct ccu_dpll_rate_tbl *rate_tbl; +}; + +struct ccu_dpll +{ + struct ccu_common common; + struct ccu_dpll_config dpll; +}; + +#define DPLL_RATE(_rate, _reg0, _reg1, _reg2, _reg3, _reg4, _reg5, _reg6, _reg7) \ +{ \ + .rate = (_rate), \ + .reg0 = (_reg0), \ + .reg1 = (_reg1), \ + .reg2 = (_reg2), \ + .reg3 = (_reg3), \ + .reg4 = (_reg4), \ + .reg5 = (_reg5), \ + .reg6 = (_reg6), \ + .reg7 = (_reg7), \ +} + +#define _SPACEMIT_CCU_DPLL_CONFIG(_table, _size) \ +{ \ + .rate_tbl = (struct ccu_dpll_rate_tbl *)_table, \ + .tbl_size = _size, \ +} + +#define SPACEMIT_CCU_DPLL(_struct, _name, _table, _size, \ + _base_type, _reg_ctrl, _reg_sel, _is_pll, _flags) \ +struct ccu_dpll _struct = \ +{ \ + .dpll = _SPACEMIT_CCU_DPLL_CONFIG(_table, _size), \ + .common = \ + { \ + .reg_ctrl = _reg_ctrl, \ + .reg_sel = _reg_sel, \ + .base_type = _base_type, \ + .is_pll = RT_FALSE, \ + .cell.name = _name, \ + .cell.ops = &ccu_dpll_ops, \ + .cell.flags = _flags, \ + }, \ +} + +extern const struct rt_clk_ops ccu_dpll_ops; + +rt_inline struct ccu_dpll *cell_to_ccu_dpll(struct rt_clk_cell *cell) +{ + struct ccu_common *common = cell_to_ccu_common(cell); + + return rt_container_of(common, struct ccu_dpll, common); +} + +#endif /* __CCU_DPLL_H__ */ diff --git a/bsp/spacemit/dm/clk/ccu_mix.c b/bsp/spacemit/dm/clk/ccu_mix.c new file mode 100644 index 000000000000..9cc6a85511e6 --- /dev/null +++ b/bsp/spacemit/dm/clk/ccu_mix.c @@ -0,0 +1,712 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include "ccu_mix.h" + +#define DBG_TAG "clk.ccu.mix" +#define DBG_LVL DBG_INFO +#include + +#define TIMEOUT_LIMIT 20000 /* Max timeout 10000us */ + +static int twsi8_reg_val = 0x04; +static const char *tswi8_clk_name = "twsi8_clk"; + +static void ccu_mix_disable(struct rt_clk_cell *cell) +{ + rt_uint32_t tmp; + rt_ubase_t level, rate; + struct ccu_mix *mix = cell_to_ccu_mix(cell); + struct ccu_common *common = &mix->common; + struct ccu_gate_config *gate = mix->gate; + + if (!gate) + { + return; + } + + if (!rt_strcmp(cell->name, tswi8_clk_name)) + { + twsi8_reg_val &= ~gate->gate_mask; + twsi8_reg_val |= gate->val_disable; + tmp = twsi8_reg_val; + + if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 || + common->reg_type == CLK_DIV_TYPE_2REG_FC_V4) + { + HWREG32(common->base + common->reg_sel) = tmp; + } + else + { + HWREG32(common->base + common->reg_ctrl) = tmp; + } + + return; + } + + if (common->lock) + { + level = rt_spin_lock_irqsave(common->lock); + } + + if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 || + common->reg_type == CLK_DIV_TYPE_2REG_FC_V4) + { + tmp = HWREG32(common->base + common->reg_sel); + } + else + { + tmp = HWREG32(common->base + common->reg_ctrl); + } + + tmp &= ~gate->gate_mask; + tmp |= gate->val_disable; + + if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 || + common->reg_type == CLK_DIV_TYPE_2REG_FC_V4) + { + HWREG32(common->base + common->reg_sel) = tmp; + } + else + { + HWREG32(common->base + common->reg_ctrl) = tmp; + } + + if (common->lock) + { + rt_spin_unlock_irqrestore(common->lock, level); + } + + if (gate->flags & SPACEMIT_CLK_GATE_NEED_DELAY) + { + rate = rt_clk_cell_get_rate(cell); + + if (rate == 0) + { + LOG_E("%s clock rate is 0", cell->name); + } + else + { + /* Need delay 2M cycles. */ + rt_hw_us_delay(RT_DIV_ROUND_UP(2000000, rate)); + } + } +} + +static rt_err_t ccu_mix_enable(struct rt_clk_cell *cell) +{ + rt_ubase_t level, rate; + rt_uint32_t tmp, val = 0, timeout_power = 1; + struct ccu_mix *mix = cell_to_ccu_mix(cell); + struct ccu_common *common = &mix->common; + struct ccu_gate_config *gate = mix->gate; + + if (!gate) + { + return RT_EOK; + } + + if (!rt_strcmp(cell->name, tswi8_clk_name)) + { + twsi8_reg_val &= ~gate->gate_mask; + twsi8_reg_val |= gate->val_enable; + tmp = twsi8_reg_val; + + if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 || + common->reg_type == CLK_DIV_TYPE_2REG_FC_V4) + { + HWREG32(common->base + common->reg_sel) = tmp; + } + else + { + HWREG32(common->base + common->reg_ctrl) = tmp; + } + + return RT_EOK; + } + + if (common->lock) + { + level = rt_spin_lock_irqsave(common->lock); + } + + if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 || + common->reg_type == CLK_DIV_TYPE_2REG_FC_V4) + { + tmp = HWREG32(common->base + common->reg_sel); + } + else + { + tmp = HWREG32(common->base + common->reg_ctrl); + } + + tmp &= ~gate->gate_mask; + tmp |= gate->val_enable; + + if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 || + common->reg_type == CLK_DIV_TYPE_2REG_FC_V4) + { + HWREG32(common->base + common->reg_sel) = tmp; + } + else + { + HWREG32(common->base + common->reg_ctrl) = tmp; + } + + if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 || + common->reg_type == CLK_DIV_TYPE_2REG_FC_V4) + { + val = HWREG32(common->base + common->reg_sel); + } + else + { + val = HWREG32(common->base + common->reg_ctrl); + } + + if (common->lock) + { + rt_spin_unlock_irqrestore(common->lock, level); + } + + while ((val & gate->gate_mask) != gate->val_enable && timeout_power < TIMEOUT_LIMIT) + { + rt_hw_us_delay(timeout_power); + + if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 || + common->reg_type == CLK_DIV_TYPE_2REG_FC_V4) + { + val = HWREG32(common->base + common->reg_sel); + } + else + { + val = HWREG32(common->base + common->reg_ctrl); + } + + timeout_power *= 10; + } + + if (timeout_power > 1) + { + if (val == tmp) + { + LOG_E("%s write clk_gate timeout occur, read pass after %d us delay", + cell->name, timeout_power); + } + else + { + LOG_E("%s write clk_gate timeout after %d us", cell->name, timeout_power); + } + } + + if (gate->flags & SPACEMIT_CLK_GATE_NEED_DELAY) + { + rate = rt_clk_cell_get_rate(cell); + + if (rate == 0) + { + LOG_E("%s clock rate is 0", cell->name); + } + else + { + /* Need delay 2M cycles. */ + rt_hw_us_delay(RT_DIV_ROUND_UP(2000000, rate)); + } + } + + return RT_EOK; +} + +static rt_bool_t ccu_mix_is_enabled(struct rt_clk_cell *cell) +{ + rt_uint32_t tmp; + rt_ubase_t level; + struct ccu_mix *mix = cell_to_ccu_mix(cell); + struct ccu_common *common = &mix->common; + struct ccu_gate_config *gate = mix->gate; + + if (!gate) + { + return RT_TRUE; + } + + if (!rt_strcmp(cell->name, tswi8_clk_name)) + { + return (twsi8_reg_val & gate->gate_mask) == gate->val_enable; + } + + if (common->lock) + { + level = rt_spin_lock_irqsave(common->lock); + } + + if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 || + common->reg_type == CLK_DIV_TYPE_2REG_FC_V4) + { + tmp = HWREG32(common->base + common->reg_sel); + } + else + { + tmp = HWREG32(common->base + common->reg_ctrl); + } + + if (common->lock) + { + rt_spin_unlock_irqrestore(common->lock, level); + } + + return (tmp & gate->gate_mask) == gate->val_enable; +} + +static rt_ubase_t ccu_mix_recalc_rate(struct rt_clk_cell *cell, rt_ubase_t parent_rate) +{ + rt_ubase_t val; + rt_uint32_t reg, div_val = 0; + struct ccu_mix *mix = cell_to_ccu_mix(cell); + struct ccu_common *common = &mix->common; + struct ccu_div_config *div = mix->div; + struct ccu_mux_config *mux = mix->mux ? mix->mux : RT_NULL; + + if (!div) + { + if (mux && common->rate && common->rate != parent_rate) + { + parent_rate = common->rate; + } + + if (mix->factor) + { + val = parent_rate * mix->factor->mul / mix->factor->div; + } + else + { + val = parent_rate; + } + + goto _end; + } + + if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 || + common->reg_type == CLK_DIV_TYPE_2REG_FC_V4) + { + reg = HWREG32(common->base + common->reg_sel); + } + else + { + reg = HWREG32(common->base + common->reg_ctrl); + } + + val = reg >> div->shift; + val &= (1 << div->width) - 1; + + if (div->clk_flags & CLK_DIVIDER_POWER_OF_TWO) + { + div_val = 1 << val; + } + else if (div->table) + { + const struct ccu_div_table *clkt; + + for (clkt = div->table; clkt->div; ++clkt) + { + if (clkt->val == val) + { + div_val = clkt->div; + break; + } + } + } + else + { + div_val = val + 1; + } + + if (!div_val) + { + val = parent_rate; + } + else + { + val = RT_DIV_ROUND_UP_ULL((rt_uint64_t)parent_rate, div_val); + } + +_end: + common->rate = val; + + return val; +} + +static rt_base_t ccu_mix_round_rate(struct rt_clk_cell *cell, rt_ubase_t drate, rt_ubase_t *prate) +{ + return drate; +} + +static rt_err_t ccu_mix_trigger_fc(struct rt_clk_cell *cell) +{ + rt_ubase_t val = 0; + rt_err_t err = RT_EOK; + rt_uint32_t timeout = 50; + struct ccu_mix *mix = cell_to_ccu_mix(cell); + struct ccu_common *common = &mix->common; + + if (common->reg_type == CLK_DIV_TYPE_1REG_FC_V2 || + common->reg_type == CLK_DIV_TYPE_2REG_FC_V4 || + common->reg_type == CLK_DIV_TYPE_1REG_FC_DIV_V5 || + common->reg_type == CLK_DIV_TYPE_1REG_FC_MUX_V6) + { + timeout = 50; + val = HWREG32(common->base + common->reg_ctrl); + val |= common->fc; + HWREG32(common->base + common->reg_ctrl) = val; + + do { + val = HWREG32(common->base + common->reg_ctrl); + --timeout; + + if (!(val & common->fc)) + { + break; + } + } while (timeout); + + if (timeout == 0) + { + timeout = 5000; + + do { + val = HWREG32(common->base + common->reg_ctrl); + --timeout; + + if (!(val & common->fc)) + { + break; + } + } while (timeout); + + if (timeout == 0) + { + err = -RT_ETIMEOUT; + } + } + } + + return err; +} + +static rt_ubase_t ccu_mix_calc_best_rate(struct rt_clk_cell *cell, + rt_ubase_t rate, rt_uint32_t *mux_val, rt_uint32_t *div_val) +{ + rt_uint32_t div_max; + rt_ubase_t parent_rate = 0, best_rate = 0; + struct rt_clk_cell *parent; + struct ccu_mix *mix = cell_to_ccu_mix(cell); + struct ccu_div_config *div = mix->div? mix->div: RT_NULL; + + for (int i = 0; i < cell->parents_nr; ++i) + { + parent = rt_clk_cell_get_parent_by_index(cell, i); + + if (!parent) + { + continue; + } + + parent_rate = rt_clk_cell_get_rate(parent); + + if (div) + { + div_max = 1 << div->width; + } + else + { + div_max = 1; + } + + for (int j = 1; j <= div_max; ++j) + { + if (div && div->clk_flags & CLK_DIVIDER_POWER_OF_TWO) + { + int d; + + if (div->clk_flags & CLK_DIVIDER_ALLOW_ZERO) + { + d = j - 1; + } + + if (rt_abs(parent_rate / RT_BIT(d) - rate) < rt_abs(best_rate - rate)) + { + best_rate = RT_DIV_ROUND_UP_ULL(parent_rate, RT_BIT(d)); + *mux_val = i; + *div_val = d; + } + + continue; + } + + if (rt_abs(parent_rate / j - rate) < rt_abs(best_rate - rate)) + { + best_rate = RT_DIV_ROUND_UP_ULL(parent_rate, j); + *mux_val = i; + *div_val = j - 1; + } + } + } + + return best_rate; +} + +static rt_err_t ccu_mix_set_rate(struct rt_clk_cell *cell, rt_ubase_t rate, rt_ubase_t parent_rate) +{ + rt_err_t err = RT_EOK; + rt_ubase_t level, best_rate; + rt_uint32_t cur_mux, cur_div, mux_val = 0, div_val = 0, reg = 0; + struct ccu_mix *mix = cell_to_ccu_mix(cell); + struct ccu_common *common = &mix->common; + struct ccu_div_config *div = mix->div? mix->div: RT_NULL; + struct ccu_mux_config *mux = mix->mux? mix->mux: RT_NULL; + + if (!div && !mux) + { + return RT_EOK; + } + + best_rate = ccu_mix_calc_best_rate(cell, rate, &mux_val, &div_val); + common->rate = best_rate; + + if (!rt_strcmp(cell->name, tswi8_clk_name)) + { + if (mux) + { + cur_mux = twsi8_reg_val >> mux->shift; + cur_mux &= (1 << mux->width) - 1; + + if (cur_mux != mux_val) + { + rt_clk_cell_set_parent(cell, rt_clk_cell_get_parent_by_index(cell, mux_val)); + } + } + + return RT_EOK; + } + + if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 || + common->reg_type == CLK_DIV_TYPE_2REG_FC_V4) + { + reg = HWREG32(common->base + common->reg_sel); + } + else + { + reg = HWREG32(common->base + common->reg_ctrl); + } + + if (mux) + { + cur_mux = reg >> mux->shift; + cur_mux &= (1 << mux->width) - 1; + + if (cur_mux != mux_val) + { + rt_clk_cell_set_parent(cell, rt_clk_cell_get_parent_by_index(cell, mux_val)); + } + } + + if (div) + { + cur_div = reg >> div->shift; + cur_div &= (1 << div->width) - 1; + + if (cur_div == div_val) + { + return RT_EOK; + } + } + else + { + return RT_EOK; + } + + level = rt_spin_lock_irqsave(common->lock); + + if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 || + common->reg_type == CLK_DIV_TYPE_2REG_FC_V4) + { + reg = HWREG32(common->base + common->reg_sel); + } + else + { + reg = HWREG32(common->base + common->reg_ctrl); + } + + reg &= ~RT_GENMASK(div->width + div->shift - 1, div->shift); + + if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 || + common->reg_type == CLK_DIV_TYPE_2REG_FC_V4) + { + HWREG32(common->base + common->reg_sel) = reg | (div_val << div->shift); + } + else + { + HWREG32(common->base + common->reg_ctrl) = reg | (div_val << div->shift); + } + + if (common->reg_type == CLK_DIV_TYPE_1REG_FC_V2 || + common->reg_type == CLK_DIV_TYPE_2REG_FC_V4 || + common->reg_type == CLK_DIV_TYPE_1REG_FC_DIV_V5) + { + err = ccu_mix_trigger_fc(cell); + } + + rt_spin_unlock_irqrestore(common->lock, level); + + if (err) + { + LOG_E("%s:%s timeout", __func__, cell->name); + } + + return RT_EOK; +} + +static rt_err_t ccu_mix_set_parent(struct rt_clk_cell *cell, rt_uint8_t idx) +{ + rt_ubase_t level; + rt_uint32_t reg = 0; + rt_err_t err = RT_EOK; + struct ccu_mix *mix = cell_to_ccu_mix(cell); + struct ccu_common *common = &mix->common; + struct ccu_mux_config *mux = mix->mux; + + if (!mux) + { + return RT_EOK; + } + + if (mux->table) + { + idx = mux->table[idx]; + } + + if (!rt_strcmp(cell->name, tswi8_clk_name)) + { + twsi8_reg_val &= ~RT_GENMASK(mux->width + mux->shift - 1, mux->shift); + twsi8_reg_val |= (idx << mux->shift); + reg = twsi8_reg_val; + + if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 || + common->reg_type == CLK_DIV_TYPE_2REG_FC_V4) + { + HWREG32(common->base + common->reg_sel) = reg; + } + else + { + HWREG32(common->base + common->reg_ctrl) = reg; + } + + return RT_EOK; + } + + level = rt_spin_lock_irqsave(common->lock); + + if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 || + common->reg_type == CLK_DIV_TYPE_2REG_FC_V4) + { + reg = HWREG32(common->base + common->reg_sel); + } + else + { + reg = HWREG32(common->base + common->reg_ctrl); + } + + reg &= ~RT_GENMASK(mux->width + mux->shift - 1, mux->shift); + + if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 || + common->reg_type == CLK_DIV_TYPE_2REG_FC_V4) + { + HWREG32(common->base + common->reg_sel) = reg | (idx << mux->shift); + } + else + { + HWREG32(common->base + common->reg_ctrl) = reg | (idx << mux->shift); + } + + if (common->reg_type == CLK_DIV_TYPE_1REG_FC_V2 || + common->reg_type == CLK_DIV_TYPE_2REG_FC_V4 || + common->reg_type == CLK_DIV_TYPE_1REG_FC_MUX_V6) + { + err = ccu_mix_trigger_fc(cell); + } + + rt_spin_unlock_irqrestore(common->lock, level); + + if (err) + { + LOG_E("%s:%s timeout", __func__, cell->name); + } + + return RT_EOK; +} + +static rt_uint8_t ccu_mix_get_parent(struct rt_clk_cell *cell) +{ + rt_uint32_t reg; + rt_uint8_t parent; + struct ccu_mix *mix = cell_to_ccu_mix(cell); + struct ccu_common *common = &mix->common; + struct ccu_mux_config *mux = mix->mux; + + if (!mux) + { + return 0; + } + + if (!rt_strcmp(cell->name, tswi8_clk_name)) + { + parent = twsi8_reg_val >> mux->shift; + parent &= (1 << mux->width) - 1; + + return parent; + } + + if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3 || + common->reg_type == CLK_DIV_TYPE_2REG_FC_V4) + { + reg = HWREG32(common->base + common->reg_sel); + } + else + { + reg = HWREG32(common->base + common->reg_ctrl); + } + + parent = reg >> mux->shift; + parent &= (1 << mux->width) - 1; + + if (mux->table) + { + for (int i = 0; i < cell->parents_nr; ++i) + { + if (mux->table[i] == parent) + { + return i; + } + } + } + + return parent; +} + +const struct rt_clk_ops ccu_mix_ops = +{ + .disable = ccu_mix_disable, + .enable = ccu_mix_enable, + .is_enabled = ccu_mix_is_enabled, + .recalc_rate = ccu_mix_recalc_rate, + .round_rate = ccu_mix_round_rate, + .set_rate = ccu_mix_set_rate, + .set_parent = ccu_mix_set_parent, + .get_parent = ccu_mix_get_parent, +}; diff --git a/bsp/spacemit/dm/clk/ccu_mix.h b/bsp/spacemit/dm/clk/ccu_mix.h new file mode 100644 index 000000000000..88c0c9cacc2d --- /dev/null +++ b/bsp/spacemit/dm/clk/ccu_mix.h @@ -0,0 +1,422 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __CCU_MIX_H__ +#define __CCU_MIX_H__ + +#include "ccu.h" + +struct ccu_gate_config +{ + rt_uint32_t gate_mask; + rt_uint32_t val_enable; + rt_uint32_t val_disable; +#define SPACEMIT_CLK_GATE_NEED_DELAY RT_BIT(0) + rt_uint32_t flags; +}; + +struct ccu_factor_config +{ + rt_uint32_t div; + rt_uint32_t mul; +}; + +struct ccu_mux_config +{ + rt_uint8_t shift; + rt_uint8_t width; + const rt_uint8_t *table; +}; + +struct ccu_div_table +{ + rt_uint32_t val; + rt_uint32_t div; +}; + +struct ccu_div_config +{ + rt_uint8_t shift; + rt_uint8_t width; + rt_uint32_t max; + rt_uint32_t offset; + rt_uint32_t clk_flags; + struct ccu_div_table *table; +}; + +struct ccu_mix +{ + struct ccu_common common; + struct ccu_gate_config *gate; + struct ccu_factor_config *factor; + struct ccu_div_config *div; + struct ccu_mux_config *mux; +}; + +#define CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, _flags) \ +(&(struct ccu_gate_config) \ +{ \ + .gate_mask = _gate_mask, \ + .val_enable = _val_enable, \ + .val_disable = _val_disable, \ + .flags = _flags, \ +}) + +#define CCU_FACTOR_INIT(_div, _mul) \ +(&(struct ccu_factor_config)\ +{ \ + .div = _div, \ + .mul = _mul, \ +}) + +#define CCU_MUX_INIT(_shift, _width, _table) \ +(&(struct ccu_mux_config) \ +{ \ + .shift = _shift, \ + .width = _width, \ + .table = _table, \ +}) + +#define CCU_DIV_INIT(_shift, _width, _table, _clk_flags) \ +(&(struct ccu_div_config) \ +{ \ + .shift = _shift, \ + .width = _width, \ + .table = _table, \ + .clk_flags = _clk_flags, \ +}) + +#define SPACEMIT_CCU_GATE(_struct, _name, _parent, _base_type, _reg, \ + _gate_mask, _val_enable, _val_disable, _flags) \ +struct ccu_mix _struct = \ +{ \ + .gate = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0), \ + .common = \ + { \ + .reg_ctrl = _reg, \ + .base_type = _base_type, \ + .cell.name = _name, \ + .cell.parent_name = _parent, \ + .cell.parents_nr = 1, \ + .cell.ops = &ccu_mix_ops, \ + .cell.flags = _flags, \ + }, \ +} + +#define SPACEMIT_CCU_GATE_NO_PARENT(_struct, _name, _parent, _base_type, _reg, \ + _gate_mask, _val_enable, _val_disable, _flags) \ +struct ccu_mix _struct = \ +{ \ + .gate = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0), \ + .common = \ + { \ + .reg_ctrl = _reg, \ + .base_type = _base_type, \ + .cell.name = _name, \ + .cell.parent_name = _parent, \ + .cell.parents_nr = 1, \ + .cell.ops = &ccu_mix_ops, \ + .cell.flags = _flags, \ + }, \ +} + +#define SPACEMIT_CCU_FACTOR(_struct, _name, _parent, _div, _mul) \ +struct ccu_mix _struct = \ +{ \ + .factor = CCU_FACTOR_INIT(_div, _mul), \ + .common = \ + { \ + .cell.name = _name, \ + .cell.parent_name = _parent, \ + .cell.parents_nr = 1, \ + .cell.ops = &ccu_mix_ops, \ + }, \ +} + +#define SPACEMIT_CCU_MUX(_struct, _name, _parents, _base_type, _reg, \ + _shift, _width, _flags) \ +struct ccu_mix _struct = \ +{ \ + .mux = CCU_MUX_INIT(_shift, _width, RT_NULL),\ + .common = \ + { \ + .reg_ctrl = _reg, \ + .base_type = _base_type, \ + .cell.name = _name, \ + .cell.parent_names = _parents, \ + .cell.parents_nr = RT_ARRAY_SIZE(_parents), \ + .cell.ops = &ccu_mix_ops, \ + .cell.flags = _flags, \ + } \ +} + +#define SPACEMIT_CCU_DIV(_struct, _name, _parent, _base_type, _reg, \ + _shift, _width, _flags) \ +struct ccu_mix _struct = \ +{ \ + .div = CCU_DIV_INIT(_shift, _width, RT_NULL, 0), \ + .common = \ + { \ + .reg_ctrl = _reg, \ + .base_type = _base_type, \ + .cell.name = _name, \ + .cell.parent_name = _parent, \ + .cell.parents_nr = 1, \ + .cell.ops = &ccu_mix_ops, \ + .cell.flags = _flags, \ + } \ +} + +#define SPACEMIT_CCU_DIV_FLAG(_struct, _name, _parent, _base_type, _reg, \ + _shift, _width, _div_flags, _flags) \ +struct ccu_mix _struct = \ +{ \ + .div = CCU_DIV_INIT(_shift, _width, RT_NULL, _div_flags), \ + .common = \ + { \ + .reg_ctrl = _reg, \ + .base_type = _base_type, \ + .cell.name = _name, \ + .cell.parent_name = _parent, \ + .cell.parents_nr = 1, \ + .cell.ops = &ccu_mix_ops, \ + .cell.flags = _flags, \ + } \ +} + +#define SPACEMIT_CCU_GATE_FACTOR(_struct, _name, _parent, _base_type, _reg, \ + _gate_mask, _val_enable, _val_disable, _div, _mul, _flags) \ +struct ccu_mix _struct = \ +{ \ + .gate = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0), \ + .factor = CCU_FACTOR_INIT(_div, _mul), \ + .common = \ + { \ + .reg_ctrl = _reg, \ + .base_type = _base_type, \ + .cell.name = _name, \ + .cell.parent_name = _parent, \ + .cell.parents_nr = 1, \ + .cell.ops = &ccu_mix_ops, \ + .cell.flags = _flags, \ + } \ +} + +#define SPACEMIT_CCU_MUX_GATE(_struct, _name, _parents, _base_type, _reg, \ + _shift, _width, _gate_mask, _val_enable, _val_disable, _flags) \ +struct ccu_mix _struct = \ +{ \ + .gate = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0), \ + .mux = CCU_MUX_INIT(_shift, _width, RT_NULL), \ + .common = \ + { \ + .reg_ctrl = _reg, \ + .base_type = _base_type, \ + .cell.name = _name, \ + .cell.parent_names = _parents, \ + .cell.parents_nr = RT_ARRAY_SIZE(_parents), \ + .cell.ops = &ccu_mix_ops, \ + .cell.flags = _flags, \ + } \ +} + +#define SPACEMIT_CCU_DIV_GATE(_struct, _name, _parent, _base_type, _reg, \ + _shift, _width, _gate_mask, _val_enable, _val_disable, _flags) \ +struct ccu_mix _struct = \ +{ \ + .gate = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0), \ + .div = CCU_DIV_INIT(_shift, _width, RT_NULL, 0), \ + .common = \ + { \ + .reg_ctrl = _reg, \ + .base_type = _base_type, \ + .cell.name = _name, \ + .cell.parent_name = _parent, \ + .cell.parents_nr = 1, \ + .cell.ops = &ccu_mix_ops, \ + .cell.flags = _flags, \ + } \ +} + +#define SPACEMIT_CCU_DIV_MUX_GATE(_struct, _name, _parents, _base_type, _reg_ctrl, \ + _mshift, _mwidth, _muxshift, _muxwidth, \ + _gate_mask, _val_enable, _val_disable, _flags) \ +struct ccu_mix _struct = \ +{ \ + .gate = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0), \ + .div = CCU_DIV_INIT(_mshift, _mwidth, RT_NULL, 0), \ + .mux = CCU_MUX_INIT(_muxshift, _muxwidth, RT_NULL), \ + .common = \ + { \ + .reg_ctrl = _reg_ctrl, \ + .base_type = _base_type, \ + .cell.name = _name, \ + .cell.parent_names = _parents, \ + .cell.parents_nr = RT_ARRAY_SIZE(_parents), \ + .cell.ops = &ccu_mix_ops, \ + .cell.flags = _flags, \ + }, \ +} + +#define SPACEMIT_CCU_DIV2_FC_MUX_GATE(_struct, _name, _parents, _base_type, _reg_ctrl, _reg_sel, \ + _mshift, _mwidth, _fc, _muxshift, _muxwidth, _gate_mask, \ + _val_enable, _val_disable, _flags) \ +struct ccu_mix _struct = \ +{ \ + .gate = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0), \ + .div = CCU_DIV_INIT(_mshift, _mwidth, RT_NULL, 0), \ + .mux = CCU_MUX_INIT(_muxshift, _muxwidth, RT_NULL), \ + .common = \ + { \ + .reg_type = CLK_DIV_TYPE_2REG_FC_V4, \ + .reg_ctrl = _reg_ctrl, \ + .reg_sel = _reg_sel, \ + .fc = _fc, \ + .base_type = _base_type, \ + .cell.name = _name, \ + .cell.parent_names = _parents, \ + .cell.parents_nr = RT_ARRAY_SIZE(_parents), \ + .cell.ops = &ccu_mix_ops, \ + .cell.flags = _flags, \ + }, \ +} + + +#define SPACEMIT_CCU_DIV_FC_MUX_GATE(_struct, _name, _parents, _base_type, _reg_ctrl, \ + _mshift, _mwidth, _fc, _muxshift, _muxwidth, _gate_mask, \ + _val_enable, _val_disable, _flags) \ +struct ccu_mix _struct = \ +{ \ + .gate = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0), \ + .div = CCU_DIV_INIT(_mshift, _mwidth, RT_NULL, 0), \ + .mux = CCU_MUX_INIT(_muxshift, _muxwidth, RT_NULL), \ + .common = \ + { \ + .reg_type = CLK_DIV_TYPE_1REG_FC_V2, \ + .reg_ctrl = _reg_ctrl, \ + .fc = _fc, \ + .base_type = _base_type, \ + .cell.name = _name, \ + .cell.parent_names = _parents, \ + .cell.parents_nr = RT_ARRAY_SIZE(_parents), \ + .cell.ops = &ccu_mix_ops, \ + .cell.flags = _flags, \ + }, \ +} + +#define SPACEMIT_CCU_DIV_MFC_MUX_GATE(_struct, _name, _parents, _base_type, _reg_ctrl, \ + _mshift, _mwidth, _fc, _muxshift, _muxwidth, _gate_mask, \ + _val_enable, _val_disable, _flags) \ +struct ccu_mix _struct = \ +{ \ + .gate = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0), \ + .div = CCU_DIV_INIT(_mshift, _mwidth, RT_NULL, 0), \ + .mux = CCU_MUX_INIT(_muxshift, _muxwidth, RT_NULL), \ + .common = \ + { \ + .reg_type = CLK_DIV_TYPE_1REG_FC_MUX_V6, \ + .reg_ctrl = _reg_ctrl, \ + .fc = _fc, \ + .base_type = _base_type, \ + .cell.name = _name, \ + .cell.parent_names = _parents, \ + .cell.parents_nr = RT_ARRAY_SIZE(_parents), \ + .cell.ops = &ccu_mix_ops, \ + .cell.flags = _flags, \ + }, \ +} + +#define SPACEMIT_CCU_DIV_FC_WITH_GATE(_struct, _name, _parent, _base_type, _reg_ctrl, \ + _mshift, _mwidth, _fc, _gate_mask, _val_enable, _val_disable, _flags) \ +struct ccu_mix _struct = \ +{ \ + .gate = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0), \ + .div = CCU_DIV_INIT(_mshift, _mwidth, RT_NULL, 0), \ + .common = \ + { \ + .reg_type = CLK_DIV_TYPE_1REG_FC_V2, \ + .reg_ctrl = _reg_ctrl, \ + .fc = _fc, \ + .base_type = _base_type, \ + .cell.name = _name, \ + .cell.parent_name = _parent, \ + .cell.parents_nr = 1, \ + .cell.ops = &ccu_mix_ops, \ + .cell.flags = _flags, \ + }, \ +} + +#define SPACEMIT_CCU_DIV_MUX(_struct, _name, _parents, _base_type, _reg_ctrl, \ + _mshift, _mwidth, _muxshift, _muxwidth, _flags) \ +struct ccu_mix _struct = \ +{ \ + .div = CCU_DIV_INIT(_mshift, _mwidth, RT_NULL, 0), \ + .mux = CCU_MUX_INIT(_muxshift, _muxwidth, RT_NULL), \ + .common = \ + { \ + .reg_ctrl = _reg_ctrl, \ + .base_type = _base_type, \ + .cell.name = _name, \ + .cell.parent_names = _parents, \ + .cell.parents_nr = RT_ARRAY_SIZE(_parents), \ + .cell.ops = &ccu_mix_ops, \ + .cell.flags = _flags, \ + }, \ +} + +#define SPACEMIT_CCU_DIV_FC_MUX(_struct, _name, _parents, _base_type, _reg_ctrl, \ + _mshift, _mwidth, _fc, _muxshift, _muxwidth, _flags) \ +struct ccu_mix _struct = \ +{ \ + .div = CCU_DIV_INIT(_mshift, _mwidth, RT_NULL, 0), \ + .mux = CCU_MUX_INIT(_muxshift, _muxwidth, RT_NULL), \ + .common = \ + { \ + .reg_type = CLK_DIV_TYPE_1REG_FC_V2, \ + .reg_ctrl = _reg_ctrl, \ + .fc = _fc, \ + .base_type = _base_type, \ + .cell.name = _name, \ + .cell.parent_names = _parents, \ + .cell.parents_nr = RT_ARRAY_SIZE(_parents), \ + .cell.ops = &ccu_mix_ops, \ + .cell.flags = _flags, \ + }, \ +} + +#define SPACEMIT_CCU_MUX_FC(_struct, _name, _parents, _base_type, _reg_ctrl, \ + _fc, _muxshift, _muxwidth, _flags) \ +struct ccu_mix _struct = \ +{ \ + .mux = CCU_MUX_INIT(_muxshift, _muxwidth, RT_NULL), \ + .common = \ + { \ + .reg_type = CLK_DIV_TYPE_1REG_FC_V2, \ + .reg_ctrl = _reg_ctrl, \ + .fc = _fc, \ + .base_type = _base_type, \ + .cell.name = _name, \ + .cell.parent_names = _parents, \ + .cell.parents_nr = RT_ARRAY_SIZE(_parents), \ + .cell.ops = &ccu_mix_ops, \ + .cell.flags = _flags, \ + }, \ +} + +extern const struct rt_clk_ops ccu_mix_ops; + +rt_inline struct ccu_mix *cell_to_ccu_mix(struct rt_clk_cell *cell) +{ + struct ccu_common *common = cell_to_ccu_common(cell); + + return rt_container_of(common, struct ccu_mix, common); +} + +#endif /* __CCU_MIX_H__ */ diff --git a/bsp/spacemit/dm/clk/ccu_pll.c b/bsp/spacemit/dm/clk/ccu_pll.c new file mode 100644 index 000000000000..a1b0270fb3ca --- /dev/null +++ b/bsp/spacemit/dm/clk/ccu_pll.c @@ -0,0 +1,321 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include "ccu_pll.h" + +#define DBG_TAG "clk.ccu.pll" +#define DBG_LVL DBG_INFO +#include + +#define PLL_MIN_FREQ 600000000 +#define PLL_MAX_FREQ 3400000000 +#define PLL_DELAYTIME 590 /* 590 * 5us */ + +#define pll_readl(reg) HWREG32(reg) +#define pll_readl_pll_swcr1(p) pll_readl(p.base + p.reg_ctrl) +#define pll_readl_pll_swcr2(p) pll_readl(p.base + p.reg_sel) +#define pll_readl_pll_swcr3(p) pll_readl(p.base + p.reg_xtc) + +#define pll_writel(val, reg) HWREG32(reg) = val; +#define pll_writel_pll_swcr1(val, p) pll_writel(val, p.base + p.reg_ctrl) +#define pll_writel_pll_swcr2(val, p) pll_writel(val, p.base + p.reg_sel) +#define pll_writel_pll_swcr3(val, p) pll_writel(val, p.base + p.reg_xtc) + +/* Unified pllx_swcr1 for pll1~3 */ +union pllx_swcr1 +{ + struct + { + rt_uint32_t reg5:8; + rt_uint32_t reg6:8; + rt_uint32_t reg7:8; + rt_uint32_t reg8:8; + } b; + rt_uint32_t v; +}; + +/* Unified pllx_swcr2 for pll1~3 */ +union pllx_swcr2 +{ + struct + { + rt_uint32_t div1_en:1; + rt_uint32_t div2_en:1; + rt_uint32_t div3_en:1; + rt_uint32_t div4_en:1; + rt_uint32_t div5_en:1; + rt_uint32_t div6_en:1; + rt_uint32_t div7_en:1; + rt_uint32_t div8_en:1; + rt_uint32_t reserved1:4; + rt_uint32_t atest_en:1; + rt_uint32_t cktest_en:1; + rt_uint32_t dtest_en:1; + rt_uint32_t rdo:2; + rt_uint32_t mon_cfg:4; + rt_uint32_t reserved2:11; + } b; + rt_uint32_t v; +}; + +/* Unified pllx_swcr3 for pll1~3 */ +union pllx_swcr3 +{ + struct + { + rt_uint32_t div_frc:24; + rt_uint32_t div_int:7; + rt_uint32_t pll_en:1; + } b; + rt_uint32_t v; +}; + +static rt_bool_t ccu_pll_is_enabled(struct rt_clk_cell *cell) +{ + rt_bool_t enabled; + union pllx_swcr3 swcr3; + struct ccu_pll *p = cell_to_ccu_pll(cell); + + swcr3.v = pll_readl_pll_swcr3(p->common); + enabled = !!swcr3.b.pll_en; + + return enabled; +} + +/* Frequency unit Mhz, return pll vco freq */ +static rt_ubase_t __get_vco_freq(struct rt_clk_cell *cell) +{ + rt_uint32_t div_int, div_frc, reg5, reg6, reg7, reg8, size; + union pllx_swcr1 swcr1; + union pllx_swcr3 swcr3; + struct ccu_pll_rate_tbl *freq_pll_regs_table; + struct ccu_pll *p = cell_to_ccu_pll(cell); + + swcr1.v = pll_readl_pll_swcr1(p->common); + swcr3.v = pll_readl_pll_swcr3(p->common); + + reg5 = swcr1.b.reg5; + reg6 = swcr1.b.reg6; + reg7 = swcr1.b.reg7; + reg8 = swcr1.b.reg8; + + div_int = swcr3.b.div_int; + div_frc = swcr3.b.div_frc; + + freq_pll_regs_table = p->pll.rate_tbl; + size = p->pll.tbl_size; + + for (int i = 0; i < size; ++i) + { + struct ccu_pll_rate_tbl *item = &freq_pll_regs_table[i]; + + if (item->reg5 == reg5 && item->reg6 == reg6 && + item->reg7 == reg7 && item->reg8 == reg8 && + item->div_int == div_int && item->div_frac == div_frc) + { + return item->rate; + } + } + + LOG_E("Unknown rate for clock %s", cell->name); + + return 0; +} + +static rt_err_t ccu_pll_enable(struct rt_clk_cell *cell) +{ + rt_ubase_t level; + rt_uint32_t delaytime = PLL_DELAYTIME; + union pllx_swcr3 swcr3; + struct ccu_pll *p = cell_to_ccu_pll(cell); + + if (ccu_pll_is_enabled(cell)) + { + return RT_EOK; + } + + level = rt_spin_lock_irqsave(p->common.lock); + + swcr3.v = pll_readl_pll_swcr3(p->common); + swcr3.b.pll_en = 1; + pll_writel_pll_swcr3(swcr3.v, p->common); + + rt_spin_unlock_irqrestore(p->common.lock, level); + + /* Check lock status */ + rt_hw_us_delay(50); + + while ((!(HWREG32(p->pll.lock_base + p->pll.reg_lock) & p->pll.lock_enable_bit)) && delaytime) + { + rt_hw_us_delay(5); + --delaytime; + } + + if (!delaytime) + { + LOG_E("%s enabling didn't get stable within 3000us", cell->name); + } + + return RT_EOK; +} + +static void ccu_pll_disable(struct rt_clk_cell *cell) +{ + rt_ubase_t level; + union pllx_swcr3 swcr3; + struct ccu_pll *p = cell_to_ccu_pll(cell); + + level = rt_spin_lock_irqsave(p->common.lock); + + swcr3.v = pll_readl_pll_swcr3(p->common); + swcr3.b.pll_en = 0; + pll_writel_pll_swcr3(swcr3.v, p->common); + + rt_spin_unlock_irqrestore(p->common.lock, level); +} + +static rt_ubase_t ccu_pll_recalc_rate(struct rt_clk_cell *cell, rt_ubase_t parent_rate) +{ + return __get_vco_freq(cell); +} + +static rt_base_t ccu_pll_round_rate(struct rt_clk_cell *cell, rt_ubase_t drate, rt_ubase_t *prate) +{ + rt_ubase_t max_rate = 0; + struct ccu_pll *p = cell_to_ccu_pll(cell); + struct ccu_pll_config *params = &p->pll; + + if (drate > PLL_MAX_FREQ || drate < PLL_MIN_FREQ) + { + LOG_E("%s %lu rate out of range", cell->name, drate); + return -RT_EINVAL; + } + + if (params->rate_tbl) + { + for (int i = 0; i < params->tbl_size; ++i) + { + struct ccu_pll_rate_tbl *item = ¶ms->rate_tbl[i]; + + if (item->rate <= drate) + { + if (max_rate < item->rate) + { + max_rate = item->rate; + } + } + } + } + else + { + LOG_E("%s don't find freq table for pll", cell->name); + } + + return max_rate; +} + +/* + * PLL rate change requires sequence: + * clock off -> change rate setting -> clock on + * This function doesn't really change rate, but cache the config + */ +static rt_err_t ccu_pll_set_rate(struct rt_clk_cell *cell, rt_ubase_t rate, rt_ubase_t parent_rate) +{ + rt_uint32_t div_int, div_frc, reg5 = 0, reg6 = 0, reg7 = 0, reg8 = 0; + rt_bool_t found = RT_FALSE, pll_enabled = RT_FALSE; + rt_ubase_t level; + union pllx_swcr1 swcr1; + union pllx_swcr3 swcr3; + struct ccu_pll *p = cell_to_ccu_pll(cell); + struct ccu_pll_config *params = &p->pll; + + if (ccu_pll_is_enabled(cell)) + { + pll_enabled = RT_TRUE; + ccu_pll_disable(cell); + } + + __get_vco_freq(cell); + + /* Setp 1: calculate fbd frcd kvco and band */ + if (params->rate_tbl) + { + for (int i = 0; i < params->tbl_size; ++i) + { + struct ccu_pll_rate_tbl *item = ¶ms->rate_tbl[i]; + + if (rate == item->rate) + { + found = RT_TRUE; + + reg5 = item->reg5; + reg6 = item->reg6; + reg7 = item->reg7; + reg8 = item->reg8; + div_int = item->div_int; + div_frc = item->div_frac; + + break; + } + } + + if (!found) + { + return -RT_EINVAL; + } + } + else + { + LOG_E("%s don't find freq table for pll", cell->name); + + if (pll_enabled) + { + ccu_pll_enable(cell); + } + + return -RT_EINVAL; + } + + level = rt_spin_lock_irqsave(p->common.lock); + + /* Setp 2: set pll kvco/band and fbd/frcd setting */ + swcr1.v = pll_readl_pll_swcr1(p->common); + swcr1.b.reg5 = reg5; + swcr1.b.reg6 = reg6; + swcr1.b.reg7 = reg7; + swcr1.b.reg8 = reg8; + pll_writel_pll_swcr1(swcr1.v, p->common); + + swcr3.v = pll_readl_pll_swcr3(p->common); + swcr3.b.div_int = div_int; + swcr3.b.div_frc = div_frc; + pll_writel_pll_swcr3(swcr3.v, p->common); + + rt_spin_unlock_irqrestore(p->common.lock, level); + + if (pll_enabled) + { + ccu_pll_enable(cell); + } + + LOG_D("%s: %s rate %lu->%lu", __func__, clk->name, old_rate, new_rate); + + return RT_EOK; +} + +const struct rt_clk_ops ccu_pll_ops = +{ + .enable = ccu_pll_enable, + .disable = ccu_pll_disable, + .is_enabled = ccu_pll_is_enabled, + .recalc_rate = ccu_pll_recalc_rate, + .round_rate = ccu_pll_round_rate, + .set_rate = ccu_pll_set_rate, +}; diff --git a/bsp/spacemit/dm/clk/ccu_pll.h b/bsp/spacemit/dm/clk/ccu_pll.h new file mode 100644 index 000000000000..531a9363198e --- /dev/null +++ b/bsp/spacemit/dm/clk/ccu_pll.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __CCU_PLL_H__ +#define __CCU_PLL_H__ + +#include "ccu.h" + +struct ccu_pll_rate_tbl +{ + rt_uint64_t rate; + rt_uint32_t reg5; + rt_uint32_t reg6; + rt_uint32_t reg7; + rt_uint32_t reg8; + rt_uint32_t div_int; + rt_uint32_t div_frac; +}; + +struct ccu_pll_config +{ + rt_uint32_t tbl_size; + struct ccu_pll_rate_tbl *rate_tbl; + + void *lock_base; + rt_uint32_t reg_lock; + rt_uint32_t lock_enable_bit; +}; + +struct ccu_pll +{ + struct ccu_common common; + struct ccu_pll_config pll; +}; + +#define PLL_RATE(_rate, _reg5, _reg6, _reg7, _reg8, _div_int, _div_frac) \ +{ \ + .rate = (_rate), \ + .reg5 = (_reg5), \ + .reg6 = (_reg6), \ + .reg7 = (_reg7), \ + .reg8 = (_reg8), \ + .div_int = (_div_int), \ + .div_frac = (_div_frac), \ +} + +#define _SPACEMIT_CCU_PLL_CONFIG(_table, _size, _reg_lock, _lock_enable_bit) \ +{ \ + .rate_tbl = (struct ccu_pll_rate_tbl *)_table, \ + .tbl_size = _size, \ + .reg_lock = _reg_lock, \ + .lock_enable_bit = _lock_enable_bit, \ +} + +#define SPACEMIT_CCU_PLL(_struct, _name, _table, _size, _base_type, \ + _reg_ctrl, _reg_sel, _reg_xtc, \ + _reg_lock, _lock_enable_bit, _is_pll, _flags) \ +struct ccu_pll _struct = \ +{ \ + .pll = _SPACEMIT_CCU_PLL_CONFIG(_table, _size, _reg_lock, _lock_enable_bit), \ + .common = \ + { \ + .reg_ctrl = _reg_ctrl, \ + .reg_sel = _reg_sel, \ + .reg_xtc = _reg_xtc, \ + .base_type = _base_type, \ + .is_pll = _is_pll, \ + .cell.name = _name, \ + .cell.ops = &ccu_pll_ops, \ + .cell.flags = _flags, \ + }, \ +} + +extern const struct rt_clk_ops ccu_pll_ops; + +rt_inline struct ccu_pll *cell_to_ccu_pll(struct rt_clk_cell *cell) +{ + struct ccu_common *common = cell_to_ccu_common(cell); + + return rt_container_of(common, struct ccu_pll, common); +} + +#endif /* __CCU_PLL_H__ */ diff --git a/bsp/spacemit/dm/clock_time/Kconfig b/bsp/spacemit/dm/clock_time/Kconfig new file mode 100644 index 000000000000..aff885faa4c0 --- /dev/null +++ b/bsp/spacemit/dm/clock_time/Kconfig @@ -0,0 +1,3 @@ +config RT_CLOCK_TIME_SPACEMIT_K1X + bool "Spacemit k1x Timer" + default n diff --git a/bsp/spacemit/dm/clock_time/SConscript b/bsp/spacemit/dm/clock_time/SConscript new file mode 100644 index 000000000000..427251006439 --- /dev/null +++ b/bsp/spacemit/dm/clock_time/SConscript @@ -0,0 +1,12 @@ +from building import * + +cwd = GetCurrentDir() +src = [] +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_CLOCK_TIME_SPACEMIT_K1X']): + src += ['clock_time-k1x.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/clock_time/clock_time-k1x.c b/bsp/spacemit/dm/clock_time/clock_time-k1x.c new file mode 100644 index 000000000000..f61f45983f1b --- /dev/null +++ b/bsp/spacemit/dm/clock_time/clock_time-k1x.c @@ -0,0 +1,667 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include +#include +#include + +#define DBG_TAG "clock_timer.k1x" +#define DBG_LVL DBG_INFO +#include + +#define TMR_CCR 0x000c +#define TMR_TN_MM(n, m) (0x0010 + ((n) << 4) + ((m) << 2)) +#define TMR_CR(n) (0x0090 + ((n) << 2)) +#define TMR_SR(n) (0x0080 + ((n) << 2)) +#define TMR_IER(n) (0x0060 + ((n) << 2)) +#define TMR_PLVR(n) (0x0040 + ((n) << 2)) +#define TMR_PLCR(n) (0x0050 + ((n) << 2)) +#define TMR_WMER 0x0068 +#define TMR_WMR 0x006c +#define TMR_WVR 0x00cc +#define TMR_WSR 0x00c0 +#define TMR_ICR(n) (0x0070 + ((n) << 2)) +#define TMR_WICR 0x00c4 +#define TMR_CER 0x0000 +#define TMR_CMR 0x0004 +#define TMR_WCR 0x00c8 +#define TMR_WFAR 0x00b0 +#define TMR_WSAR 0x00b4 +#define TMR_CRSR 0x0008 + +#define TMR_CCR_CS_0(x) (((x) & 0x3) << 0) +#define TMR_CCR_CS_1(x) (((x) & 0x3) << 2) +#define TMR_CCR_CS_2(x) (((x) & 0x3) << 5) + +#define MAX_DELTA 0xfffffffe +#define MIN_DELTA 5 + +#define SPACEMIT_MAX_COUNTER 3 +#define SPACEMIT_MAX_TIMER 3 + +#define TMR_CER_COUNTER(cid) (1 << (cid)) +#define SPACEMIT_ALL_COUNTERS ((1 << SPACEMIT_MAX_COUNTER) - 1) + +#define SPACEMIT_TIMER_ALL_CPU 0xffffffff + +#define CLOCK_32KHZ 32768 + +struct spacemit_timer; + +struct spacemit_timer_counter +{ + struct rt_clock_timer_device parent; + struct rt_clock_timer_info info; + + struct spacemit_timer *timer; + + int irq; + rt_uint32_t cid; + rt_uint32_t cycle; + rt_uint32_t freq; +}; + +#define raw_to_spacemit_timer_counter(raw) rt_container_of(raw, struct spacemit_timer_counter, parent) + +struct spacemit_timer +{ + void *base; + struct rt_clk *clk; + struct rt_reset_control *rstc; + + rt_uint32_t tid; + rt_uint32_t freq; + rt_uint32_t fc_freq; + rt_uint32_t apb_freq; + rt_uint32_t loop_delay_fastclk; + + struct spacemit_timer_counter counter[SPACEMIT_MAX_COUNTER]; + struct rt_spinlock tm_lock; +}; + +static rt_err_t timer_counter_switch_clock(struct spacemit_timer *timer, rt_uint32_t freq); + +static void timer_write_check(struct spacemit_timer *timer, + rt_uint32_t reg, rt_uint32_t val, rt_uint32_t mask, + rt_bool_t clr, rt_bool_t clk_switch) +{ + int loop = 3, retry = 100; + rt_uint32_t t_read, t_check = clr ? !val : val; + +_retry: + HWREG32(timer->base + reg) = val; + + if (clk_switch) + { + timer_counter_switch_clock(timer, timer->fc_freq); + } + + t_read = HWREG32(timer->base + reg); + + while (((t_read & mask) != (t_check & mask)) && loop) + { + /* Avoid trying frequently to worsen bus contention */ + rt_hw_us_delay(30); + + t_read = HWREG32(timer->base + reg); + --loop; + + if (!loop) + { + loop = 3; + + if (--retry) + { + goto _retry; + } + else + { + return; + } + } + } +} + +static rt_err_t timer_counter_switch_clock(struct spacemit_timer *timer, rt_uint32_t freq) +{ + rt_uint32_t ccr, val, mask; + + ccr = HWREG32(timer->base + TMR_CCR); + + switch (timer->tid) + { + case 0: + mask = TMR_CCR_CS_0(3); + break; + case 1: + mask = TMR_CCR_CS_1(3); + break; + case 2: + mask = TMR_CCR_CS_2(3); + break; + default: + return -RT_EINVAL; + } + + ccr &= ~mask; + + if (freq == timer->fc_freq) + { + val = 0; + } + else if (freq == CLOCK_32KHZ) + { + val = 1; + } + else + { + LOG_E("Timer %d: invalid clock rate %u", timer->tid, freq); + return -RT_EINVAL; + } + + switch (timer->tid) + { + case 0: + ccr |= TMR_CCR_CS_0(val); + break; + case 1: + ccr |= TMR_CCR_CS_1(val); + break; + case 2: + ccr |= TMR_CCR_CS_2(val); + break; + } + + timer_write_check(timer, TMR_CCR, ccr, mask, RT_FALSE, RT_FALSE); + + return RT_EOK; +} + +static void timer_counter_disable(struct spacemit_timer_counter *cnt) +{ + rt_uint32_t cer; + rt_bool_t clk_switch = RT_FALSE; + struct spacemit_timer *timer = cnt->timer; + + if (cnt->freq != timer->fc_freq) + { + clk_switch = RT_TRUE; + } + + /* Disable counter */ + cer = HWREG32(timer->base + TMR_CER); + timer_write_check(timer, TMR_CER, (cer & ~(1 << cnt->cid)), (1 << cnt->cid), RT_FALSE, clk_switch); +} + +static void timer_counter_enable(struct spacemit_timer_counter *cnt) +{ + rt_uint32_t cer; + struct spacemit_timer *timer = cnt->timer; + + /* Switch to original clock */ + if (cnt->freq != timer->fc_freq) + { + timer_counter_switch_clock(timer, cnt->freq); + } + + /* Enable timer */ + cer = HWREG32(timer->base + TMR_CER); + + timer_write_check(timer, TMR_CER, (cer | (1 << cnt->cid)), (1 << cnt->cid), RT_FALSE, RT_FALSE); +} + +static void spacemit_timer_init(struct rt_clock_timer_device *timer_dev, rt_uint32_t state) +{ + RT_UNUSED(timer_dev); + RT_UNUSED(state); +} + +static rt_err_t spacemit_timer_start(struct rt_clock_timer_device *timer_dev, + rt_uint32_t cycle, rt_clock_timer_mode_t mode) +{ + rt_ubase_t level; + struct spacemit_timer_counter *cnt = raw_to_spacemit_timer_counter(timer_dev); + + if (mode != CLOCK_TIMER_MODE_ONESHOT) + { + return -RT_ENOSYS; + } + + level = rt_spin_lock_irqsave(&cnt->timer->tm_lock); + + /* If the timer counter is enabled, first disable it. */ + if (HWREG32(cnt->timer->base + TMR_CER) & (1 << cnt->cid)) + { + timer_counter_disable(cnt); + } + + /* Setup new counter value */ + timer_write_check(cnt->timer, TMR_TN_MM(cnt->cid, 0), (cycle - 1), (rt_uint32_t)(-1), RT_FALSE, RT_FALSE); + + /* enable the matching interrupt */ + timer_write_check(cnt->timer, TMR_IER(cnt->cid), 0x1, 0x1, RT_FALSE, RT_FALSE); + + timer_counter_enable(cnt); + + cnt->cycle = cycle; + + rt_spin_unlock_irqrestore(&cnt->timer->tm_lock, level); + + return RT_EOK; +} + +static void spacemit_timer_stop(struct rt_clock_timer_device *timer_dev) +{ + rt_ubase_t level; + struct spacemit_timer_counter *cnt = raw_to_spacemit_timer_counter(timer_dev); + + level = rt_spin_lock_irqsave(&cnt->timer->tm_lock); + + timer_counter_disable(cnt); + + rt_spin_unlock_irqrestore(&cnt->timer->tm_lock, level); +} + +static rt_err_t spacemit_timer_ctrl(struct rt_clock_timer_device *timer_dev, + rt_uint32_t cmd, void *args) +{ + rt_ubase_t level; + rt_err_t err = RT_EOK; + struct spacemit_timer_counter *cnt = raw_to_spacemit_timer_counter(timer_dev); + + switch (cmd) + { + case CLOCK_TIMER_CTRL_FREQ_SET: + if (!args) + { + err = -RT_EINVAL; + break; + } + + level = rt_spin_lock_irqsave(&cnt->timer->tm_lock); + err = timer_counter_switch_clock(cnt->timer, *(rt_int32_t *)args); + if (!err) + { + cnt->freq = *(rt_int32_t *)args; + } + rt_spin_unlock_irqrestore(&cnt->timer->tm_lock, level); + break; + + case CLOCK_TIMER_CTRL_STOP: + spacemit_timer_stop(timer_dev); + break; + + case CLOCK_TIMER_CTRL_INFO_GET: + if (args) + { + rt_memcpy(args, &cnt->info, sizeof(cnt->info)); + } + else + { + err = -RT_EINVAL; + } + break; + + case CLOCK_TIMER_CTRL_MODE_SET: + err = spacemit_timer_start(timer_dev, cnt->cycle, + (rt_clock_timer_mode_t)(rt_ubase_t)args); + break; + + default: + err = -RT_EINVAL; + break; + } + + return err; +} + +const static struct rt_clock_timer_ops spacemit_timer_ops = +{ + .init = spacemit_timer_init, + .start = spacemit_timer_start, + .stop = spacemit_timer_stop, + .control = spacemit_timer_ctrl, +}; + +static void spacemit_timer_isr(int irqno, void *param) +{ + rt_ubase_t level; + struct spacemit_timer_counter *cnt = param; + + level = rt_spin_lock_irqsave(&cnt->timer->tm_lock); + + /* We only use match #0 for the counter. */ + if (HWREG32(cnt->timer->base + TMR_SR(cnt->cid)) & 0x1) + { + timer_counter_disable(cnt); + + /* Disable the interrupt. */ + timer_write_check(cnt->timer, TMR_IER(cnt->cid), 0, 0x7, RT_FALSE, RT_FALSE); + /* Clear interrupt status */ + timer_write_check(cnt->timer, TMR_ICR(cnt->cid), 0x1, 0x7, RT_TRUE, RT_FALSE); + + rt_spin_unlock_irqrestore(&cnt->timer->tm_lock, level); + + rt_clock_timer_isr(&cnt->parent); + + return; + } + + rt_spin_unlock_irqrestore(&cnt->timer->tm_lock, level); +} + +static void spacemit_timer_free(struct spacemit_timer *timer) +{ + if (timer->base) + { + rt_iounmap(timer->base); + } + + if (!rt_is_err_or_null(timer->clk)) + { + rt_clk_put(timer->clk); + } + + rt_free(timer); +} + +static rt_err_t spacemit_timer_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + const char *dev_name; + rt_uint32_t val, delay; + struct rt_device *dev = &pdev->parent; + struct rt_ofw_node *np = dev->ofw_node, *child_np; + struct spacemit_timer *timer = rt_calloc(1, sizeof(*timer)); + + if (!timer) + { + return -RT_ENOMEM; + } + + timer->base = rt_dm_dev_iomap(dev, 0); + + if (!timer->base) + { + err = -RT_EIO; + goto _fail; + } + + if (rt_is_err(timer->clk = rt_clk_get_by_index(dev, 0))) + { + err = rt_ptr_err(timer->clk); + goto _fail; + } + + if (rt_is_err(timer->rstc = rt_reset_control_get_by_index(dev, 0))) + { + err = rt_ptr_err(timer->rstc); + goto _fail; + } + + if ((err = rt_dm_dev_prop_read_u32(dev, "spacemit,timer-id", &timer->tid))) + { + goto _fail; + } + + if (timer->tid >= SPACEMIT_MAX_TIMER) + { + err = -RT_EFULL; + goto _fail; + } + + /* Timer's fast clock and apb frequency */ + if ((err = rt_dm_dev_prop_read_u32(dev, "spacemit,timer-fastclk-frequency", &timer->fc_freq))) + { + goto _fail; + } + + if ((err = rt_dm_dev_prop_read_u32(dev, "spacemit,timer-apb-frequency", &timer->apb_freq))) + { + goto _fail; + } + + if ((err = rt_dm_dev_prop_read_u32(dev, "spacemit,timer-frequency", &timer->freq))) + { + goto _fail; + } + + /* + * Need use loop for more safe register's accessing, + * so at here dynamically calculate the loop time. + */ + if (!timer->fc_freq || !timer->apb_freq) + { + err = -RT_EINVAL; + goto _fail; + } + + if ((err = rt_clk_prepare_enable(timer->clk))) + { + goto _fail; + } + + if ((err = rt_clk_set_rate(timer->clk, timer->fc_freq))) + { + goto _fail; + } + + rt_reset_control_deassert(timer->rstc); + + /* + * The calculation formula for the loop cycle is: + * + * (1) need wait for 2 timer's clock cycle: + * 1 2 + * ------- x 2 = ------- + * fc_freq fc_freqtimer_counter_enable(evt); + * + * (2) convert to apb clock cycle: + * 2 1 apb_freq * 2 + * ------- / -------- = ---------------- + * fc_freq apb_freq fc_freq + * + * (3) every apb register's accessing will take 8 apb clock cycle, + * also consider add extral one more time for safe way; + * so finally need loop times for the apb register accessing: + * + * (apb_freq * 2) + * ------------------ / 8 + 1 + * fc_freq + */ + delay = ((timer->apb_freq * 2) / timer->fc_freq / 8) + 1; + timer->loop_delay_fastclk = delay; + + rt_spin_lock_init(&timer->tm_lock); + + /* Switch to fastclk before disable all counters. */ + timer_counter_switch_clock(timer, timer->fc_freq); + + /* Disalbe all counters */ + val = HWREG32(timer->base + TMR_CER) & ~SPACEMIT_ALL_COUNTERS; + HWREG32(timer->base + TMR_CER) = val; + + /* Disable matching interrupt */ + HWREG32(timer->base + TMR_IER(0)) = 0x0; + HWREG32(timer->base + TMR_IER(1)) = 0x0; + HWREG32(timer->base + TMR_IER(2)) = 0x0; + + while (delay--) + { + /* Clear pending interrupt status */ + HWREG32(timer->base + TMR_ICR(0)) = 0x1; + HWREG32(timer->base + TMR_ICR(1)) = 0x1; + HWREG32(timer->base + TMR_ICR(2)) = 0x1; + HWREG32(timer->base + TMR_CER) = val; + } + + rt_ofw_foreach_available_child_node(np, child_np) + { + rt_uint32_t cpu, ratio; + struct spacemit_timer_counter *cnt; + + if (!rt_ofw_node_is_compatible(child_np, "spacemit,timer-match")) + { + continue; + } + + if (rt_ofw_prop_read_u32(child_np, "spacemit,timer-counter-id", &val)) + { + continue; + } + + if (val >= SPACEMIT_MAX_TIMER) + { + LOG_W("Found a counter %s with id = %d > %d", + rt_ofw_node_full_name(child_np), val, SPACEMIT_MAX_TIMER); + continue; + } + + cnt = &timer->counter[val]; + cnt->cid = val; + cnt->freq = timer->freq; + + if (cnt->timer) + { + LOG_W("Found a repeat counter %s with id = %d", + rt_ofw_node_full_name(child_np), cnt->cid); + continue; + } + + if (cnt->timer) + { + LOG_W("Found a repeat counter %s with id = %d", + rt_ofw_node_full_name(child_np), cnt->cid); + continue; + } + + if (rt_ofw_prop_read_bool(child_np, "spacemit,timer-broadcast")) + { + cpu = SPACEMIT_TIMER_ALL_CPU; + } + else + { + cpu = rt_hw_cpu_id(); + rt_ofw_prop_read_u32(child_np, "spacemit,timer-counter-cpu", &cpu); + } + + if ((cnt->irq = rt_ofw_get_irq(child_np, 0)) < 0) + { + continue; + } + + /* Hareware init */ + if (timer_counter_switch_clock(timer, cnt->freq)) + { + continue; + } + + ratio = timer->fc_freq / timer->freq; + delay = timer->loop_delay_fastclk * ratio; + + /* Set timer to free-running mode */ + val = HWREG32(timer->base + TMR_CMR) | TMR_CER_COUNTER(cnt->cid); + HWREG32(timer->base + TMR_CMR) = val; + + /* Free-running */ + HWREG32(timer->base + TMR_PLCR(cnt->cid)) = 0x0; + /* Clear status */ + HWREG32(timer->base + TMR_ICR(cnt->cid)) = 0x7; + + /* Enable counter */ + val = HWREG32(timer->base + TMR_CER) | TMR_CER_COUNTER(cnt->cid); + HWREG32(timer->base + TMR_CER) = val; + + while (delay--) + { + HWREG32(timer->base + TMR_CER) = val; + } + + cnt->timer = timer; + + cnt->parent.ops = &spacemit_timer_ops; + cnt->parent.info = &cnt->info; + cnt->parent.freq = cnt->freq; + + cnt->info.maxfreq = cnt->freq; + cnt->info.minfreq = cnt->freq; + cnt->info.maxcnt = 0xffffffff; + cnt->info.cntmode = CLOCK_TIMER_CNTMODE_UP; + + rt_dm_dev_set_name_auto(&cnt->parent.parent, "timer"); + dev_name = rt_dm_dev_get_name(&cnt->parent.parent); + + rt_hw_interrupt_install(cnt->irq, spacemit_timer_isr, cnt, dev_name); + rt_hw_interrupt_umask(cnt->irq); + + if (cpu != SPACEMIT_TIMER_ALL_CPU) + { + RT_IRQ_AFFINITY_DECLARE(affinity) = { 0 }; + + RT_IRQ_AFFINITY_SET(affinity, cpu); + + rt_pic_irq_set_affinity(cnt->irq, affinity); + } + + rt_clock_timer_register(&cnt->parent, dev_name, RT_NULL); + } + + dev->user_data = timer; + + return RT_EOK; + +_fail: + spacemit_timer_free(timer); + + return err; +} + +static rt_err_t spacemit_timer_remove(struct rt_platform_device *pdev) +{ + struct spacemit_timer *timer = pdev->parent.user_data; + + for (int i = 0; i < SPACEMIT_MAX_TIMER; ++i) + { + struct spacemit_timer_counter *cnt = &timer->counter[i]; + + if (!cnt->timer) + { + continue; + } + + spacemit_timer_stop(&cnt->parent); + + rt_hw_interrupt_mask(cnt->irq); + rt_pic_detach_irq(cnt->irq, cnt); + + rt_device_unregister(&cnt->parent.parent); + } + + spacemit_timer_free(timer); + + return RT_EOK; +} + +static const struct rt_ofw_node_id spacemit_timer_ofw_ids[] = +{ + { .compatible = "spacemit,soc-timer" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_timer_driver = +{ + .name = "clock_timer-spacemit", + .ids = spacemit_timer_ofw_ids, + + .probe = spacemit_timer_probe, + .remove = spacemit_timer_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(spacemit_timer_driver); diff --git a/bsp/spacemit/dm/dma/Kconfig b/bsp/spacemit/dm/dma/Kconfig new file mode 100644 index 000000000000..da72fad16b7c --- /dev/null +++ b/bsp/spacemit/dm/dma/Kconfig @@ -0,0 +1,8 @@ +config RT_DMA_MMP_PDMA + bool "Spacemit K1X MMP PDMA" + default n + +config RT_DMA_MMP_PDMA_SUPPORT_64BIT + bool "Support 64bit" + depends on RT_DMA_MMP_PDMA + default n diff --git a/bsp/spacemit/dm/dma/SConscript b/bsp/spacemit/dm/dma/SConscript new file mode 100644 index 000000000000..e8fd891561a8 --- /dev/null +++ b/bsp/spacemit/dm/dma/SConscript @@ -0,0 +1,13 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_DMA_MMP_PDMA']): + src += ['dma-mmp-pdma.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/dma/dma-mmp-pdma.c b/bsp/spacemit/dm/dma/dma-mmp-pdma.c new file mode 100644 index 000000000000..19cccc8757de --- /dev/null +++ b/bsp/spacemit/dm/dma/dma-mmp-pdma.c @@ -0,0 +1,994 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include +#include + +#define DBG_TAG "dma.mmp-pdma" +#define DBG_LVL DBG_INFO +#include + +#include + +#define DDADRH(n) (0x0300 + ((n) << 4)) +#define DSADRH(n) (0x0304 + ((n) << 4)) +#define DTADRH(n) (0x0308 + ((n) << 4)) +#define DCSR_LPAEEN RT_BIT(21) /* Long Physical Address Extension enable */ +#define DRCMR_INVALID 100 /* Max DMA request number + 1 */ +#define DCMD_BURST64 (4 << 16) /* 64 byte burst */ + +#define DCSR 0x0000 +#define DALGN 0x00a0 +#define DINT 0x00f0 +#define DDADR 0x0200 +#define DSADR(n) (0x0204 + ((n) << 4)) +#define DTADR(n) (0x0208 + ((n) << 4)) +#define DCMD 0x020c + +#define DCSR_RUN RT_BIT(31) /* Run Bit (read / write) */ +#define DCSR_NODESC RT_BIT(30) /* No-Descriptor Fetch (read / write) */ +#define DCSR_STOPIRQEN RT_BIT(29) /* Stop Interrupt Enable (read / write) */ +#define DCSR_REQPEND RT_BIT(8) /* Request Pending (read-only) */ +#define DCSR_STOPSTATE RT_BIT(3) /* Stop State (read-only) */ +#define DCSR_ENDINTR RT_BIT(2) /* End Interrupt (read / write) */ +#define DCSR_STARTINTR RT_BIT(1) /* Start Interrupt (read / write) */ +#define DCSR_BUSERR RT_BIT(0) /* Bus Error Interrupt (read / write) */ + +#define DCSR_EORIRQEN RT_BIT(28) /* End of Receive Interrupt Enable (R/W) */ +#define DCSR_EORJMPEN RT_BIT(27) /* Jump to next descriptor on EOR */ +#define DCSR_EORSTOPEN RT_BIT(26) /* STOP on an EOR */ +#define DCSR_SETCMPST RT_BIT(25) /* Set Descriptor Compare Status */ +#define DCSR_CLRCMPST RT_BIT(24) /* Clear Descriptor Compare Status */ +#define DCSR_CMPST RT_BIT(10) /* The Descriptor Compare Status */ +#define DCSR_EORINTR RT_BIT(9) /* The end of Receive */ + +#define DRCMR(n) ((((n) < 64) ? 0x0100 : 0x1100) + (((n) & 0x3f) << 2)) +#define DRCMR_MAPVLD RT_BIT(7) /* Map Valid (read / write) */ +#define DRCMR_CHLNUM 0x1f /* mask for Channel Number (read / write) */ + +#define DDADR_DESCADDR 0xfffffff0 /* Address of next descriptor (mask) */ +#define DDADR_STOP RT_BIT(0) /* Stop (read / write) */ + +#define DCMD_INCSRCADDR RT_BIT(31) /* Source Address Increment Setting. */ +#define DCMD_INCTRGADDR RT_BIT(30) /* Target Address Increment Setting. */ +#define DCMD_FLOWSRC RT_BIT(29) /* Flow Control by the source. */ +#define DCMD_FLOWTRG RT_BIT(28) /* Flow Control by the target. */ +#define DCMD_STARTIRQEN RT_BIT(22) /* Start Interrupt Enable */ +#define DCMD_ENDIRQEN RT_BIT(21) /* End Interrupt Enable */ +#define DCMD_ENDIAN RT_BIT(18) /* Device Endian-ness. */ +#define DCMD_BURST8 (1 << 16) /* 8 byte burst */ +#define DCMD_BURST16 (2 << 16) /* 16 byte burst */ +#define DCMD_BURST32 (3 << 16) /* 32 byte burst */ +#define DCMD_WIDTH1 (1 << 14) /* 1 byte width */ +#define DCMD_WIDTH2 (2 << 14) /* 2 byte width (HalfWord) */ +#define DCMD_WIDTH4 (3 << 14) /* 4 byte width (Word) */ +#define DCMD_LENGTH 0x01fff /* length mask (max = 8K - 1) */ + +#define DEFAULT_MAX_BURST_SIZE 32 +#define INVALID_BURST_SETTING -1 + +#define PDMA_MAX_DESC_BYTES DCMD_LENGTH + +#ifdef RT_DMA_MMP_PDMA_SUPPORT_64BIT +struct mmp_pdma_desc_hw +{ + rt_uint32_t ddadr; /* Points to the next descriptor + flags */ + rt_uint32_t dsadr; /* DSADR value for the current transfer */ + rt_uint32_t dtadr; /* DTADR value for the current transfer */ + rt_uint32_t dcmd; /* DCMD value for the current transfer */ + rt_uint32_t ddadrh; /* Points to the next descriptor + flags */ + rt_uint32_t dsadrh; /* DSADR value for the current transfer */ + rt_uint32_t dtadrh; /* DTADR value for the current transfer */ + rt_uint32_t rsvd; /* DCMD value for the current transfer */ +} rt_align(64); +#else +struct mmp_pdma_desc_hw +{ + rt_uint32_t ddadr; /* Points to the next descriptor + flags */ + rt_uint32_t dsadr; /* DSADR value for the current transfer */ + rt_uint32_t dtadr; /* DTADR value for the current transfer */ + rt_uint32_t dcmd; /* DCMD value for the current transfer */ +} rt_align(32); +#endif + +struct mmp_pdma_chan +{ + struct rt_dma_chan parent; + + rt_size_t desc_nr; + rt_ubase_t desc_dma; + struct mmp_pdma_desc_hw *desc; + + rt_uint32_t dcmd; + rt_uint32_t drcmr; + rt_uint32_t dev_addr; + + rt_size_t size; + rt_uint32_t bytes_residue; + rt_bool_t byte_align; + rt_bool_t pausing; + enum rt_dma_transfer_direction dir; +}; + +struct reserved_chan +{ + rt_uint32_t chan_id; + rt_uint32_t drcmr; +}; + +struct mmp_pdma_device +{ + struct rt_dma_controller parent; + + struct rt_clk *clk; + struct rt_reset_control *rstc; + + int irq; + void *base; + + rt_uint32_t max_burst_size; + + rt_uint32_t dma_channels; + struct mmp_pdma_chan *chan; + + rt_uint32_t reserved_channels_nr; + struct reserved_chan *reserved_channels; + + struct mmp_pdma_phy *phy; +}; +#define raw_to_mmp_pdma_device(raw) rt_container_of(raw, struct mmp_pdma_device, parent) +#define raw_to_mmp_pdma_device_chan(raw) rt_container_of(raw, struct mmp_pdma_chan, parent) + +static int get_max_burst_setting(rt_uint32_t max_burst_size) +{ + switch (max_burst_size) + { + case 8: + return DCMD_BURST8; + case 16: + return DCMD_BURST16; + case 32: + return DCMD_BURST32; + case 64: + return DCMD_BURST64; + default: + return INVALID_BURST_SETTING; + } +} + +static void enable_chan(struct mmp_pdma_chan *chan) +{ + int idx; + rt_uint32_t reg, dalgn, dcsr; + struct mmp_pdma_device *pdma = raw_to_mmp_pdma_device(chan->parent.ctrl); + + idx = chan - pdma->chan; + + if (chan->drcmr >= 0) + { + reg = DRCMR(chan->drcmr); + HWREG32(pdma->base + reg) = DRCMR_MAPVLD | idx; + } + + dalgn = HWREG32(pdma->base + DALGN); + if (chan->byte_align) + { + dalgn |= 1 << idx; + } + else + { + dalgn &= ~(1 << idx); + } + HWREG32(pdma->base + DALGN) = dalgn; + + reg = (idx << 2) + DCSR; + + dcsr = HWREG32(pdma->base + reg); + dcsr |= DCSR_RUN | DCSR_EORIRQEN | DCSR_EORSTOPEN; +#ifdef RT_DMA_MMP_PDMA_SUPPORT_64BIT + /* Use long descriptor mode: set DCSR_LPAEEN bit */ + dcsr |= DCSR_LPAEEN; +#endif + HWREG32(pdma->base + reg) = dcsr; +} + +static void disable_chan(struct mmp_pdma_chan *chan) +{ + int idx; + rt_uint32_t reg, dcsr, cnt = 1000; + struct mmp_pdma_device *pdma = raw_to_mmp_pdma_device(chan->parent.ctrl); + + idx = chan - pdma->chan; + + reg = (idx << 2) + DCSR; + + dcsr = HWREG32(pdma->base + reg); + dcsr &= ~(DCSR_RUN | DCSR_EORIRQEN | DCSR_EORSTOPEN); +#ifdef RT_DMA_MMP_PDMA_SUPPORT_64BIT + /* Use long descriptor mode: set DCSR_LPAEEN bit */ + dcsr &= ~DCSR_LPAEEN; +#endif + HWREG32(pdma->base + reg) = dcsr; + + /* Ensure dma is stopped. */ + dcsr = HWREG32(pdma->base + reg); + while (!(dcsr & (0x1 << 3)) && --cnt) + { + rt_hw_us_delay(10); + dcsr = HWREG32(pdma->base + reg); + } +} + +static void mmp_pdma_config_write(struct mmp_pdma_chan *chan, + struct rt_dma_slave_config *cfg, + enum rt_dma_transfer_direction direction) +{ + rt_uint32_t maxburst = 0, addr = 0; + enum rt_dma_slave_buswidth width = RT_DMA_SLAVE_BUSWIDTH_UNDEFINED; + + if (direction == RT_DMA_DEV_TO_MEM) + { + chan->dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC; + maxburst = cfg->src_maxburst; + width = cfg->src_addr_width; + addr = cfg->src_addr; + } + else if (direction == RT_DMA_MEM_TO_DEV) + { + chan->dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG; + maxburst = cfg->dst_maxburst; + width = cfg->dst_addr_width; + addr = cfg->dst_addr; + } + + if (width == RT_DMA_SLAVE_BUSWIDTH_1_BYTE) + { + chan->dcmd |= DCMD_WIDTH1; + } + else if (width == RT_DMA_SLAVE_BUSWIDTH_2_BYTES) + { + chan->dcmd |= DCMD_WIDTH2; + } + else if (width == RT_DMA_SLAVE_BUSWIDTH_4_BYTES) + { + chan->dcmd |= DCMD_WIDTH4; + } + + if (maxburst == 8) + { + chan->dcmd |= DCMD_BURST8; + } + else if (maxburst == 16) + { + chan->dcmd |= DCMD_BURST16; + } + else if (maxburst == 32) + { + chan->dcmd |= DCMD_BURST32; + } + + chan->dir = direction; + chan->dev_addr = addr; +} + +static struct rt_dma_chan *mmp_pdma_request_chan(struct rt_dma_controller *ctrl, + struct rt_device *slave, void *fw_data) +{ + int drcmr; + struct mmp_pdma_chan *chan = RT_NULL; + struct mmp_pdma_device *pdma = raw_to_mmp_pdma_device(ctrl); + struct rt_ofw_cell_args *args = fw_data; + rt_bool_t matched_reserved = RT_FALSE; + + drcmr = args ? args->args[0] : -1; + + if (drcmr >= 0) + { + for (int i = 0; i < pdma->reserved_channels_nr; ++i) + { + int chan_id = pdma->reserved_channels[i].chan_id; + + if (pdma->reserved_channels[i].drcmr == drcmr && + chan_id >= 0 && chan_id < pdma->dma_channels) + { + matched_reserved = RT_TRUE; + + if (!pdma->chan[chan_id].desc) + { + chan = &pdma->chan[chan_id]; + } + + goto _found_reserved; + } + } + } + +_found_reserved: + if (matched_reserved && !chan) + { + return rt_err_ptr(-RT_EBUSY); + } + + for (int i = 0; i < pdma->dma_channels; ++i) + { + rt_bool_t reserved = RT_FALSE; + + if (chan) + { + break; + } + + if (!pdma->chan[i].desc) + { + for (int j = 0; j < pdma->reserved_channels_nr; ++j) + { + if (pdma->reserved_channels[j].chan_id == i) + { + reserved = RT_TRUE; + break; + } + } + + if (reserved) + { + continue; + } + + chan = &pdma->chan[i]; + break; + } + } + + if (!chan) + { + return rt_err_ptr(-RT_EBUSY); + } + + chan->drcmr = drcmr; + chan->pausing = RT_FALSE; + chan->desc_nr = ARCH_PAGE_SIZE / sizeof(*chan->desc); + chan->desc = rt_dma_alloc_coherent(slave, ARCH_PAGE_SIZE, &chan->desc_dma); + + if (!chan->desc) + { + return rt_err_ptr(-RT_ENOMEM); + } + + return &chan->parent; +} + +static rt_err_t mmp_pdma_release_chan(struct rt_dma_chan *raw_chan) +{ + struct mmp_pdma_chan *chan = raw_to_mmp_pdma_device_chan(raw_chan); + + rt_dma_free_coherent(raw_chan->slave, ARCH_PAGE_SIZE, chan->desc, chan->desc_dma); + chan->desc = RT_NULL; + + return RT_EOK; +} + +static rt_err_t mmp_pdma_start(struct rt_dma_chan *raw_chan) +{ + struct mmp_pdma_chan *chan = raw_to_mmp_pdma_device_chan(raw_chan); + + if (!chan->pausing) + { + int idx; + rt_uint32_t reg; + struct mmp_pdma_device *pdma = raw_to_mmp_pdma_device(chan->parent.ctrl); + + idx = chan - pdma->chan; + reg = (idx << 4) + DDADR; + + HWREG32(pdma->base + reg) = chan->desc_dma & 0xffffffff; + #ifdef RT_DMA_MMP_PDMA_SUPPORT_64BIT + /* Config higher bits for desc address */ + HWREG32(pdma->base + DDADRH(idx)) = (rt_uint32_t)(chan->desc_dma >> 32); + #endif + } + + enable_chan(chan); + chan->bytes_residue = 0; + chan->pausing = RT_FALSE; + + return RT_EOK; +} + +static rt_err_t mmp_pdma_pause(struct rt_dma_chan *raw_chan) +{ + struct mmp_pdma_chan *chan = raw_to_mmp_pdma_device_chan(raw_chan); + + disable_chan(chan); + chan->pausing = RT_TRUE; + + return RT_EOK; +} + +static rt_err_t mmp_pdma_stop(struct rt_dma_chan *raw_chan) +{ + rt_uint32_t reg; + struct mmp_pdma_chan *chan = raw_to_mmp_pdma_device_chan(raw_chan); + struct mmp_pdma_device *pdma = raw_to_mmp_pdma_device(raw_chan->ctrl); + + disable_chan(chan); + + if (chan->drcmr >= 0) + { + /* Clear the channel mapping in DRCMR */ + reg = DRCMR(chan->drcmr); + HWREG32(pdma->base + reg) = 0; + } + + chan->bytes_residue = 0; + chan->pausing = RT_FALSE; + + return RT_EOK; +} + +static rt_err_t mmp_pdma_config(struct rt_dma_chan *raw_chan, + struct rt_dma_slave_config *conf) +{ + if (conf->src_addr_width == RT_DMA_SLAVE_BUSWIDTH_UNDEFINED) + { + conf->src_addr_width = RT_DMA_SLAVE_BUSWIDTH_4_BYTES; + } + if (conf->dst_addr_width == RT_DMA_SLAVE_BUSWIDTH_UNDEFINED) + { + conf->dst_addr_width = RT_DMA_SLAVE_BUSWIDTH_4_BYTES; + } + + return RT_EOK; +} + +static rt_err_t mmp_pdma_prep_memcpy(struct rt_dma_chan *raw_chan, + rt_ubase_t dma_addr_src, rt_ubase_t dma_addr_dst, rt_size_t len) +{ + int idx; + rt_size_t copy = 0; + rt_ubase_t desc_dma; + struct mmp_pdma_desc_hw *desc, *prev_desc; + struct mmp_pdma_chan *chan = raw_to_mmp_pdma_device_chan(raw_chan); + struct mmp_pdma_device *pdma = raw_to_mmp_pdma_device(raw_chan->ctrl); + + if (len > chan->desc_nr * PDMA_MAX_DESC_BYTES) + { + return -RT_EEMPTY; + } + + chan->byte_align = RT_FALSE; + + if (!chan->dir) + { + chan->dir = RT_DMA_MEM_TO_MEM; + chan->dcmd = DCMD_INCTRGADDR | DCMD_INCSRCADDR | get_max_burst_setting(pdma->max_burst_size); + } + + chan->size = len; + + for (idx = 0, desc_dma = chan->desc_dma; len; ++idx, desc_dma += sizeof(*desc)) + { + copy = rt_min_t(rt_size_t, len, PDMA_MAX_DESC_BYTES); + + if ((dma_addr_src & 0x7) || (dma_addr_dst & 0x7)) + { + chan->byte_align = RT_TRUE; + } + + desc = &chan->desc[idx]; + desc->dcmd = chan->dcmd | (DCMD_LENGTH & copy); + + /* + * Check whether descriptor/source-addr/target-addr is in + * region higher than 4G. If so, set related higher bits to 1. + */ + if (chan->dir == RT_DMA_MEM_TO_DEV) + { + desc->dsadr = dma_addr_src & 0xffffffff; + desc->dtadr = dma_addr_dst; + #ifdef RT_DMA_MMP_PDMA_SUPPORT_64BIT + desc->dsadrh = dma_addr_src >> 32; + desc->dtadrh = 0; + #endif + } + else if (chan->dir == RT_DMA_DEV_TO_MEM) + { + desc->dsadr = dma_addr_src; + desc->dtadr = dma_addr_dst & 0xffffffff; + #ifdef RT_DMA_MMP_PDMA_SUPPORT_64BIT + desc->dsadrh = 0; + desc->dtadrh = dma_addr_dst >> 32; + #endif + } + else if (chan->dir == RT_DMA_MEM_TO_MEM) + { + desc->dsadr = dma_addr_src & 0xffffffff; + desc->dtadr = dma_addr_dst & 0xffffffff; + #ifdef RT_DMA_MMP_PDMA_SUPPORT_64BIT + desc->dsadrh = dma_addr_src >> 32; + desc->dtadrh = dma_addr_dst >> 32; + #endif + } + + len -= copy; + + if (chan->dir == RT_DMA_MEM_TO_DEV) + { + dma_addr_src += copy; + } + else if (chan->dir == RT_DMA_DEV_TO_MEM) + { + dma_addr_dst += copy; + } + else if (chan->dir == RT_DMA_MEM_TO_MEM) + { + dma_addr_src += copy; + dma_addr_dst += copy; + } + + if (idx) + { + prev_desc = &chan->desc[idx - 1]; + + prev_desc->ddadr = desc_dma; + #ifdef RT_DMA_MMP_PDMA_SUPPORT_64BIT + prev_desc->ddadrh = desc_dma >> 32; + #endif + } + } + + prev_desc = &chan->desc[idx - 1]; + + prev_desc->ddadr = DDADR_STOP; + prev_desc->dcmd |= DCMD_ENDIRQEN; + + return RT_EOK; +} + +static rt_err_t mmp_pdma_prep_cyclic(struct rt_dma_chan *raw_chan, + rt_ubase_t dma_buf_addr, rt_size_t buf_len, rt_size_t period_len, + enum rt_dma_transfer_direction dir) +{ + int idx; + rt_ubase_t desc_dma; + rt_ubase_t dma_addr_src, dma_addr_dst; +#ifdef RT_DMA_MMP_PDMA_SUPPORT_64BIT + rt_ubase_t dma_addr_srch, dma_addr_dsth; +#endif + struct mmp_pdma_desc_hw *desc, *prev_desc; + struct mmp_pdma_chan *chan = raw_to_mmp_pdma_device_chan(raw_chan); + + if (buf_len % period_len != 0) + { + return -RT_EINVAL; + } + + if (period_len > PDMA_MAX_DESC_BYTES) + { + return -RT_EINVAL; + } + + if (buf_len > chan->desc_nr * PDMA_MAX_DESC_BYTES) + { + return -RT_EEMPTY; + } + + mmp_pdma_config_write(chan, &raw_chan->conf, dir); + + switch (dir) + { + case RT_DMA_MEM_TO_DEV: + dma_addr_src = dma_buf_addr & 0xffffffff; + dma_addr_dst = chan->dev_addr; + #ifdef RT_DMA_MMP_PDMA_SUPPORT_64BIT + dma_addr_srch = dma_buf_addr >> 32; + dma_addr_dsth = 0; + #endif + break; + + case RT_DMA_DEV_TO_MEM: + dma_addr_dst = dma_buf_addr & 0xffffffff; + dma_addr_src = chan->dev_addr; + #ifdef RT_DMA_MMP_PDMA_SUPPORT_64BIT + dma_addr_dsth = dma_buf_addr >> 32; + dma_addr_srch = 0; + #endif + break; + + default: + LOG_E("Unsupported direction for cyclic DMA"); + return -RT_EINVAL; + } + + chan->dir = dir; + chan->size = buf_len; + + for (idx = 0, desc_dma = chan->desc_dma; buf_len; ++idx, desc_dma += sizeof(*desc)) + { + desc = &chan->desc[idx]; + + desc->dcmd = chan->dcmd | DCMD_ENDIRQEN | (DCMD_LENGTH & period_len); + desc->dsadr = dma_addr_src; + desc->dtadr = dma_addr_dst; + #ifdef RT_DMA_MMP_PDMA_SUPPORT_64BIT + desc->dsadrh = dma_addr_dsth; + desc->dtadrh = dma_addr_srch; + #endif + + buf_len -= period_len; + + if (chan->dir == RT_DMA_MEM_TO_DEV) + { + dma_addr_src += period_len; + } + else + { + dma_addr_dst += period_len; + } + + if (idx) + { + prev_desc = &chan->desc[idx - 1]; + + prev_desc->ddadr = desc_dma; + #ifdef RT_DMA_MMP_PDMA_SUPPORT_64BIT + prev_desc->ddadrh = desc_dma >> 32; + #endif + } + }; + + prev_desc = &chan->desc[idx - 1]; + + /* Make the cyclic link */ + prev_desc->ddadr = chan->desc_dma; + + return RT_EOK; +} + +static rt_err_t mmp_pdma_prep_single(struct rt_dma_chan *raw_chan, + rt_ubase_t dma_buf_addr, rt_size_t buf_len, + enum rt_dma_transfer_direction dir) +{ + int idx; + rt_size_t copy = 0; + rt_ubase_t desc_dma; + struct mmp_pdma_desc_hw *desc, *prev_desc; + struct mmp_pdma_chan *chan = raw_to_mmp_pdma_device_chan(raw_chan); + + if (buf_len > chan->desc_nr * PDMA_MAX_DESC_BYTES) + { + return -RT_EEMPTY; + } + + chan->byte_align = RT_TRUE; + + mmp_pdma_config_write(chan, &raw_chan->conf, dir); + + chan->dir = dir; + chan->size = buf_len; + + for (idx = 0, desc_dma = chan->desc_dma; buf_len; ++idx, desc_dma += sizeof(*desc)) + { + copy = rt_min_t(rt_size_t, buf_len, PDMA_MAX_DESC_BYTES); + + if (dma_buf_addr & 0x7) + { + chan->byte_align = RT_TRUE; + } + + desc = &chan->desc[idx]; + desc->dcmd = chan->dcmd | (DCMD_LENGTH & copy); + + /* + * Check whether descriptor/source-addr/target-addr is in + * region higher than 4G. If so, set related higher bits to 1. + */ + if (dir == RT_DMA_MEM_TO_DEV) + { + desc->dsadr = dma_buf_addr & 0xffffffff; + desc->dtadr = chan->dev_addr; + #ifdef RT_DMA_MMP_PDMA_SUPPORT_64BIT + desc->dsadrh = dma_buf_addr >> 32; + desc->dtadrh = 0; + #endif + } + else if (dir == RT_DMA_DEV_TO_MEM) + { + desc->dsadr = chan->dev_addr; + desc->dtadr = dma_buf_addr & 0xffffffff; + #ifdef RT_DMA_MMP_PDMA_SUPPORT_64BIT + desc->dsadrh = 0; + desc->dtadrh = dma_buf_addr >> 32; + #endif + } + else + { + return -RT_EINVAL; + } + + dma_buf_addr += copy; + buf_len -= copy; + + if (idx) + { + prev_desc = &chan->desc[idx - 1]; + + prev_desc->ddadr = desc_dma; + #ifdef RT_DMA_MMP_PDMA_SUPPORT_64BIT + prev_desc->ddadrh = desc_dma >> 32; + #endif + } + } + + prev_desc = &chan->desc[idx - 1]; + + prev_desc->ddadr = DDADR_STOP; + prev_desc->dcmd |= DCMD_ENDIRQEN; + + return RT_EOK; +} + +static const struct rt_dma_controller_ops mmp_pdma_ops = +{ + .request_chan = mmp_pdma_request_chan, + .release_chan = mmp_pdma_release_chan, + .start = mmp_pdma_start, + .pause = mmp_pdma_pause, + .stop = mmp_pdma_stop, + .config = mmp_pdma_config, + .prep_memcpy = mmp_pdma_prep_memcpy, + .prep_cyclic = mmp_pdma_prep_cyclic, + .prep_single = mmp_pdma_prep_single, +}; + +static void mmp_pdma_isr(int irq, void *param) +{ + rt_uint32_t i, dint, dcsr; + struct mmp_pdma_chan *chan; + struct mmp_pdma_device *pdma = param; + + dint = HWREG32(pdma->base + DINT); + + while (dint) + { + if ((i = __rt_ffs(dint) - 1) >= pdma->dma_channels) + { + break; + } + + chan = &pdma->chan[i]; + + /* Clear IRQ */ + dcsr = HWREG32(pdma->base + (i << 2) + DCSR); + HWREG32(pdma->base + (i << 2) + DCSR) = dcsr; + + rt_dma_chan_done(&chan->parent, chan->size); + + dint &= (dint - 1); + } +} + +#ifdef RT_USING_PM +static rt_err_t mmp_pdma_pm_suspend(const struct rt_device *device, rt_uint8_t mode) +{ + struct mmp_pdma_device *pdma = device->user_data; + + rt_clk_disable_unprepare(pdma->clk); + + return RT_EOK; +} + +static void mmp_pdma_pm_resume(const struct rt_device *device, rt_uint8_t mode) +{ + struct mmp_pdma_device *pdma = device->user_data; + + rt_clk_prepare_enable(pdma->clk); +} + +static const struct rt_device_pm_ops mmp_pdma_pm_ops = +{ + .suspend = mmp_pdma_pm_suspend, + .resume = mmp_pdma_pm_resume, +}; +#endif /* RT_USING_PM */ + +static void mmp_pdma_free(struct mmp_pdma_device *pdma, struct rt_device *dev) +{ + if (pdma->base) + { + rt_iounmap(pdma->base); + } + + if (!rt_is_err_or_null(pdma->clk)) + { + rt_clk_disable_unprepare(pdma->clk); + rt_clk_put(pdma->clk); + } + + if (!rt_is_err_or_null(pdma->rstc)) + { + rt_reset_control_put(pdma->rstc); + } + + if (pdma->reserved_channels) + { + rt_free(pdma->reserved_channels); + } + + if (pdma->chan) + { + rt_free(pdma->chan); + } + + rt_free(pdma); +} + +static rt_err_t mmp_pdma_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct mmp_pdma_device *pdma = rt_calloc(1, sizeof(*pdma)); + + if (!pdma) + { + return -RT_ENOMEM; + } + + if (!(pdma->base = rt_dm_dev_iomap(dev, 0))) + { + err = -RT_EIO; + goto _fail; + } + + if ((pdma->irq = rt_dm_dev_get_irq(dev, 0)) < 0) + { + err = pdma->irq; + goto _fail; + } + + pdma->clk = rt_clk_get_by_index(dev, 0); + if (rt_is_err(pdma->clk)) + { + err = rt_ptr_err(pdma->clk); + goto _fail; + } + + if ((err = rt_clk_prepare_enable(pdma->clk))) + { + goto _fail; + } + + pdma->rstc = rt_reset_control_get_by_index(dev, 0); + if (rt_is_err(pdma->rstc)) + { + err = rt_ptr_err(pdma->rstc); + goto _fail; + } + + if ((err = rt_reset_control_deassert(pdma->rstc))) + { + goto _fail; + } + + if ((err = rt_dm_dev_prop_read_u32(dev, "#dma-channels", &pdma->dma_channels))) + { + goto _fail; + } + + if (rt_dm_dev_prop_read_u32(dev, "max-burst-size", &pdma->max_burst_size) || + get_max_burst_setting(pdma->max_burst_size) == INVALID_BURST_SETTING) + { + pdma->max_burst_size = DEFAULT_MAX_BURST_SIZE; + } + + pdma->reserved_channels_nr = rt_dm_dev_prop_count_of_size(dev, + "reserved-channels", sizeof(rt_uint32_t) * 2); + + if (pdma->reserved_channels_nr > 0) + { + pdma->reserved_channels = rt_calloc(pdma->reserved_channels_nr, sizeof(struct reserved_chan)); + + if (!pdma->reserved_channels) + { + err = -RT_ENOMEM; + goto _fail; + } + + for (int i = 0; i < pdma->reserved_channels_nr; ++i) + { + rt_dm_dev_prop_read_u32_index(dev, "reserved-channels", i * 2, + &pdma->reserved_channels[i].chan_id); + rt_dm_dev_prop_read_u32_index(dev, "reserved-channels", i * 2 + 1, + &pdma->reserved_channels[i].drcmr); + } + } + + if (!(pdma->chan = rt_calloc(pdma->dma_channels, sizeof(*pdma->chan)))) + { + err = -RT_ENOMEM; + goto _fail; + } + + pdma->parent.dev = dev; + pdma->parent.ops = &mmp_pdma_ops; + rt_dma_controller_add_direction(&pdma->parent, RT_DMA_MEM_TO_MEM); + rt_dma_controller_add_direction(&pdma->parent, RT_DMA_MEM_TO_DEV); + rt_dma_controller_add_direction(&pdma->parent, RT_DMA_DEV_TO_MEM); +#ifdef RT_DMA_MMP_PDMA_SUPPORT_64BIT + rt_dma_controller_set_addr_mask(&pdma->parent, RT_DMA_ADDR_MASK(64)); +#else + rt_dma_controller_set_addr_mask(&pdma->parent, RT_DMA_ADDR_MASK(32)); +#endif + + if ((err = rt_dma_controller_register(&pdma->parent))) + { + goto _fail; + } + + rt_hw_interrupt_install(pdma->irq, mmp_pdma_isr, pdma, "pdma"); + rt_hw_interrupt_umask(pdma->irq); + + dev->user_data = pdma; + +#ifdef RT_USING_PM + rt_pm_device_register(dev, &mmp_pdma_pm_ops); +#endif + + return RT_EOK; + +_fail: + mmp_pdma_free(pdma, dev); + + return err; +} + +static rt_err_t mmp_pdma_remove(struct rt_platform_device *pdev) +{ + struct rt_device *dev = &pdev->parent; + struct mmp_pdma_device *pdma = dev->user_data; + +#ifdef RT_USING_PM + rt_pm_device_unregister(dev); +#endif + + rt_dma_controller_unregister(&pdma->parent); + + rt_hw_interrupt_mask(pdma->irq); + rt_pic_detach_irq(pdma->irq, pdma); + + rt_reset_control_assert(pdma->rstc); + + mmp_pdma_free(pdma, dev); + + return RT_EOK; +} + +static const struct rt_ofw_node_id mmp_pdma_ofw_ids[] = +{ + { .compatible = "spacemit,pdma-1.0" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver mmp_pdma_driver = +{ + .name = "dma-mmp-pdma", + .ids = mmp_pdma_ofw_ids, + + .probe = mmp_pdma_probe, + .remove = mmp_pdma_remove, +}; + +static int mmp_pdma_drv_register(void) +{ + rt_platform_driver_register(&mmp_pdma_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(mmp_pdma_drv_register); diff --git a/bsp/spacemit/dm/dvfs/SConscript b/bsp/spacemit/dm/dvfs/SConscript new file mode 100644 index 000000000000..f56996e72966 --- /dev/null +++ b/bsp/spacemit/dm/dvfs/SConscript @@ -0,0 +1,16 @@ +from building import * + +group = [] + +if not GetDepend(['RT_USING_DVFS']): + Return('group') + +cwd = GetCurrentDir() +list = os.listdir(cwd) + +for d in list: + path = os.path.join(cwd, d) + if os.path.isfile(os.path.join(path, 'SConscript')): + group = group + SConscript(os.path.join(d, 'SConscript')) + +Return('group') diff --git a/bsp/spacemit/dm/dvfs/cpufreq/Kconfig b/bsp/spacemit/dm/dvfs/cpufreq/Kconfig new file mode 100644 index 000000000000..b0f6170177e6 --- /dev/null +++ b/bsp/spacemit/dm/dvfs/cpufreq/Kconfig @@ -0,0 +1,11 @@ +config RT_DVFS_SPACEMIT_CPUFREQ + bool "Spacemit K1/M1 CPUfreq driver" + depends on RT_USING_DVFS + depends on RT_USING_OFW + depends on SOC_SPACEMIT_K1 + depends on RT_CLK_SPACEMIT_K1X + depends on RT_REGULATOR_SPACEMIT_PMIC + default y + help + Enable CPU DVFS for the Spacemit K1/M1 shared CPU voltage domain. + Both CPU clusters and their TCM/ACE clocks are switched together. diff --git a/bsp/spacemit/dm/dvfs/cpufreq/SConscript b/bsp/spacemit/dm/dvfs/cpufreq/SConscript new file mode 100644 index 000000000000..3f1244a16cd0 --- /dev/null +++ b/bsp/spacemit/dm/dvfs/cpufreq/SConscript @@ -0,0 +1,11 @@ +from building import * + +cwd = GetCurrentDir() +src = [] + +if GetDepend(['RT_DVFS_SPACEMIT_CPUFREQ']): + src += ['dvfs-spacemit-cpufreq.c'] + +group = DefineGroup('DeviceDrivers', src, depend = ['']) + +Return('group') diff --git a/bsp/spacemit/dm/dvfs/cpufreq/dvfs-spacemit-cpufreq.c b/bsp/spacemit/dm/dvfs/cpufreq/dvfs-spacemit-cpufreq.c new file mode 100644 index 000000000000..d950bb8d9cb8 --- /dev/null +++ b/bsp/spacemit/dm/dvfs/cpufreq/dvfs-spacemit-cpufreq.c @@ -0,0 +1,864 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include +#include + +#include +#include +#include + +#define DBG_TAG "dvfs.spacemit" +#define DBG_LVL DBG_INFO +#include + +#define SPACEMIT_PRODUCT_ID_M1 0x36070000U +#define SPACEMIT_K1_MAX_FREQ 1600000000UL +#define SPACEMIT_M1_MAX_FREQ 1800000000UL +#define SPACEMIT_TURBO0_FREQ 1600000000UL +#define SPACEMIT_TURBO1_FREQ 3200000000UL +#define SPACEMIT_STABLE_FREQ 1200000000UL +#define SPACEMIT_FREQ_TOLERANCE 1000000UL +#define SPACEMIT_STABLE_TOLERANCE 50000000UL +#define SPACEMIT_DEFAULT_CCI_FREQ 614000000UL +#define SPACEMIT_DEFAULT_LATENCY_NS 200000U +#define SPACEMIT_DEFAULT_RETRY_NS 100000U +#define SPACEMIT_DRO_TABLE0_MAX 135U +#define SPACEMIT_DRO_TABLE1_MAX 142U + +struct spacemit_cpufreq_opp +{ + rt_ubase_t cluster_hz[2]; + rt_ubase_t tcm_hz; + rt_ubase_t ace_hz; +}; + +struct spacemit_cpufreq +{ + struct rt_dvfs_cpufreq cpufreq; + struct rt_platform_device *pdev; + struct rt_ofw_node *cpu_np; + struct rt_ofw_node *opp_np; + + struct rt_regulator *supply; + struct rt_clk *cluster[2]; + struct rt_clk *ace[2]; + struct rt_clk *tcm; + struct rt_clk *cci; + struct rt_clk *pll3; + struct rt_clk *hi[2]; + + struct rt_mutex lock; + rt_bool_t lock_ready; + rt_bool_t dev_registered; + rt_bool_t is_m1; + rt_uint32_t silicon_id; + rt_uint32_t opp_index; +}; + +static struct spacemit_cpufreq *spacemit_cpufreq_data; + +static rt_ubase_t rate_delta(rt_ubase_t a, rt_ubase_t b) +{ + return a > b ? a - b : b - a; +} + +static rt_bool_t rate_matches(rt_ubase_t actual, rt_ubase_t target) +{ + return rate_delta(actual, target) <= SPACEMIT_FREQ_TOLERANCE; +} + +static rt_ubase_t spacemit_mux_hw_rate(struct rt_clk *clk) +{ + rt_uint8_t parent_index; + struct rt_clk_cell *parent_cell; + + parent_index = rt_clk_cell_get_parent_index(clk->cell); + if (parent_index == RT_UINT8_MAX) + { + return 0; + } + + parent_cell = rt_clk_cell_get_parent_by_index(clk->cell, parent_index); + + return parent_cell ? rt_clk_cell_get_rate(parent_cell) : 0; +} + +static rt_err_t spacemit_get_clk(struct rt_ofw_node *np, const char *name, + struct rt_clk **out_clk) +{ + struct rt_clk *clk; + + clk = rt_ofw_get_clk_by_name(np, name); + + if (rt_is_err_or_null(clk)) + { + rt_err_t err = clk ? rt_ptr_err(clk) : -RT_ENOENT; + + LOG_E("%s: get clock %s failed: %s", + rt_ofw_node_full_name(np), name, rt_strerror(err)); + return err; + } + + *out_clk = clk; + + return RT_EOK; +} + +static rt_err_t spacemit_set_rate(struct rt_clk *clk, rt_ubase_t target, + const char *name, rt_ubase_t tolerance) +{ + rt_err_t err; + rt_ubase_t actual; + + if ((err = rt_clk_set_rate(clk, target))) + { + LOG_E("set %s to %lu Hz failed: %s", name, target, rt_strerror(err)); + return err; + } + + actual = rt_clk_get_rate(clk); + if (rate_delta(actual, target) > tolerance) + { + LOG_E("%s rate mismatch: requested %lu Hz, got %lu Hz", + name, target, actual); + return -RT_EIO; + } + + return RT_EOK; +} + +static rt_err_t spacemit_set_mux_rate(struct rt_clk *clk, rt_ubase_t target, + const char *name, rt_ubase_t tolerance) +{ + rt_err_t err; + rt_ubase_t actual; + + if ((err = rt_clk_set_rate(clk, target))) + { + LOG_E("set %s to %lu Hz failed: %s", name, target, rt_strerror(err)); + return err; + } + + actual = spacemit_mux_hw_rate(clk); + if (!actual || rate_delta(actual, target) > tolerance) + { + LOG_E("%s hardware rate mismatch: requested %lu Hz, got %lu Hz", + name, target, actual); + return -RT_EIO; + } + + return RT_EOK; +} + +static rt_err_t spacemit_set_binary_div(struct rt_clk *clk, const char *name) +{ + struct rt_clk *parent = rt_clk_get_parent(clk); + rt_ubase_t parent_rate; + + if (!parent || !(parent_rate = rt_clk_get_rate(parent))) + { + LOG_E("%s has no valid parent rate", name); + return -RT_EIO; + } + + return spacemit_set_rate(clk, parent_rate / 2, name, + SPACEMIT_FREQ_TOLERANCE); +} + +static rt_err_t spacemit_set_voltage(struct spacemit_cpufreq *priv, + rt_ubase_t uvolt) +{ + rt_err_t err = rt_regulator_set_voltage(priv->supply, uvolt, uvolt); + + if (err) + { + LOG_E("set CPU voltage to %lu uV failed: %s", uvolt, + rt_strerror(err)); + } + + return err; +} + +static int spacemit_current_voltage(struct rt_dvfs_scaling *scaling, + struct spacemit_cpufreq *priv) +{ + int uvolt = rt_regulator_get_voltage(priv->supply); + + if (uvolt <= 0 && scaling->opp_table && scaling->opp_table->current_opp) + { + uvolt = (int)scaling->opp_table->current_opp->uvolt; + } + + return uvolt; +} + +static rt_err_t spacemit_prepare_dependent_clks(struct spacemit_cpufreq *priv) +{ + rt_err_t err; + + if ((err = spacemit_set_binary_div(priv->ace[0], "ace0"))) + { + return err; + } + if ((err = spacemit_set_binary_div(priv->ace[1], "ace1"))) + { + return err; + } + + return spacemit_set_binary_div(priv->tcm, "tcm"); +} + +static rt_err_t spacemit_finish_dependent_clks(struct spacemit_cpufreq *priv, + const struct spacemit_cpufreq_opp *opp_data) +{ + rt_err_t err; + + if ((err = spacemit_set_rate(priv->tcm, opp_data->tcm_hz, "tcm", + SPACEMIT_FREQ_TOLERANCE))) + { + return err; + } + if ((err = spacemit_set_rate(priv->ace[0], opp_data->ace_hz, "ace0", + SPACEMIT_FREQ_TOLERANCE))) + { + return err; + } + + return spacemit_set_rate(priv->ace[1], opp_data->ace_hz, "ace1", + SPACEMIT_FREQ_TOLERANCE); +} + +static rt_err_t spacemit_prepare_turbo_clks(struct spacemit_cpufreq *priv, + rt_ubase_t old_freq, rt_ubase_t new_freq) +{ + rt_err_t err; + + if (new_freq < SPACEMIT_TURBO0_FREQ) + { + return RT_EOK; + } + + if (old_freq >= SPACEMIT_TURBO0_FREQ) + { + if ((err = spacemit_set_mux_rate(priv->cluster[0], + SPACEMIT_STABLE_FREQ, "cls0-stable", + SPACEMIT_STABLE_TOLERANCE))) + { + return err; + } + if ((err = spacemit_set_mux_rate(priv->cluster[1], + SPACEMIT_STABLE_FREQ, "cls1-stable", + SPACEMIT_STABLE_TOLERANCE))) + { + return err; + } + } + + if (new_freq == SPACEMIT_TURBO0_FREQ) + { + if ((err = spacemit_set_rate(priv->pll3, SPACEMIT_TURBO1_FREQ, + "pll3", SPACEMIT_FREQ_TOLERANCE))) + { + return err; + } + } + else + { + if ((err = spacemit_set_rate(priv->pll3, new_freq, "pll3", + SPACEMIT_FREQ_TOLERANCE))) + { + return err; + } + } + + if ((err = spacemit_set_mux_rate(priv->hi[0], new_freq, "c0hi", + SPACEMIT_FREQ_TOLERANCE))) + { + return err; + } + + return spacemit_set_mux_rate(priv->hi[1], new_freq, "c1hi", + SPACEMIT_FREQ_TOLERANCE); +} + +static rt_err_t spacemit_cpufreq_set_opp(struct rt_dvfs_scaling *scaling, + struct rt_dvfs_opp *opp) +{ + rt_err_t err; + int old_uvolt; + rt_bool_t voltage_raised = RT_FALSE; + rt_ubase_t old_rate[2], old_freq, new_freq; + struct spacemit_cpufreq *priv = scaling->priv; + struct spacemit_cpufreq_opp *opp_data = opp->priv; + + if (!priv || !opp_data) + { + return -RT_EINVAL; + } + + if ((err = rt_mutex_take(&priv->lock, RT_WAITING_FOREVER))) + { + return err; + } + + old_rate[0] = spacemit_mux_hw_rate(priv->cluster[0]); + old_rate[1] = spacemit_mux_hw_rate(priv->cluster[1]); + old_freq = rt_max(old_rate[0], old_rate[1]); + new_freq = rt_max(opp_data->cluster_hz[0], opp_data->cluster_hz[1]); + old_uvolt = spacemit_current_voltage(scaling, priv); + + if ((old_uvolt > 0 && opp->uvolt > (rt_ubase_t)old_uvolt) || + (old_uvolt <= 0 && new_freq > old_freq)) + { + if ((err = spacemit_set_voltage(priv, opp->uvolt))) + { + goto _out; + } + + voltage_raised = RT_TRUE; + rt_dvfs_ns_sleep(scaling->transition_latency); + } + + if ((err = spacemit_prepare_dependent_clks(priv))) + { + goto _out; + } + if ((err = spacemit_prepare_turbo_clks(priv, old_freq, new_freq))) + { + goto _out; + } + + { + rt_err_t err0, err1; + + err0 = spacemit_set_mux_rate(priv->cluster[0], opp_data->cluster_hz[0], + "cls0", SPACEMIT_FREQ_TOLERANCE); + err1 = spacemit_set_mux_rate(priv->cluster[1], opp_data->cluster_hz[1], + "cls1", SPACEMIT_FREQ_TOLERANCE); + if (err0 || err1) + { + err = err0 ? err0 : err1; + goto _out; + } + } + + if ((err = spacemit_finish_dependent_clks(priv, opp_data))) + { + goto _out; + } + + if (old_uvolt > 0 && opp->uvolt < (rt_ubase_t)old_uvolt && + !voltage_raised) + { + if ((err = spacemit_set_voltage(priv, opp->uvolt))) + { + goto _out; + } + } + + scaling->cur_freq = opp->freq; + scaling->opp_table->current_opp = opp; + + LOG_D("CPU OPP: %lu Hz @ %lu uV (hw %lu/%lu Hz)", + opp->freq, opp->uvolt, + spacemit_mux_hw_rate(priv->cluster[0]), + spacemit_mux_hw_rate(priv->cluster[1])); + +_out: + if (err && voltage_raised) + { + LOG_W("CPU clock transition failed after voltage raise; keeping %lu uV", + opp->uvolt); + } + + rt_mutex_release(&priv->lock); + + return err; +} + +static const struct rt_dvfs_scaling_ops spacemit_cpufreq_ops = +{ + .set_opp = spacemit_cpufreq_set_opp, +}; + +static int spacemit_select_opp_index(struct spacemit_cpufreq *priv) +{ + rt_uint32_t wafer = 0, product = 0, dro = 0; + struct rt_ofw_node *root, *cpus; + int index = 0; + + root = rt_ofw_find_node_by_path("/"); + if (root) + { + rt_ofw_prop_read_u32(root, "wafer-id", &wafer); + rt_ofw_prop_read_u32(root, "product-id", &product); + rt_ofw_node_put(root); + } + + priv->silicon_id = (wafer << 16) | (product & 0xffffU); + priv->is_m1 = priv->silicon_id == SPACEMIT_PRODUCT_ID_M1; + + cpus = rt_ofw_find_node_by_path("/cpus"); + if (cpus) + { + rt_ofw_prop_read_u32(cpus, "svt-dro", &dro); + rt_ofw_node_put(cpus); + } + + if (priv->is_m1) + { + if (dro <= SPACEMIT_DRO_TABLE0_MAX) + { + index = 0; + } + else if (dro <= SPACEMIT_DRO_TABLE1_MAX) + { + index = 1; + } + else + { + index = 2; + } + } + + LOG_D("silicon=0x%08x svt-dro=%u OPP table=%d max=%lu Hz", + priv->silicon_id, dro, index, + priv->is_m1 ? SPACEMIT_M1_MAX_FREQ : SPACEMIT_K1_MAX_FREQ); + + return index; +} + +static rt_err_t spacemit_parse_opps(struct spacemit_cpufreq *priv, + struct rt_dvfs_scaling *scaling) +{ + int count = 0; + struct rt_ofw_node *opp_np; + + rt_ofw_foreach_available_child_node(priv->opp_np, opp_np) + { + int hz_nr; + rt_uint32_t uvolt = 0, latency = 0; + rt_uint64_t hz[2] = {0}, tcm_hz = 0, ace_hz = 0; + struct rt_dvfs_opp *opp; + struct spacemit_cpufreq_opp *opp_data; + + hz_nr = rt_ofw_prop_read_u64_array_index(opp_np, "opp-hz", 0, + RT_ARRAY_SIZE(hz), hz); + if (hz_nr < 1 || rt_ofw_prop_read_u32(opp_np, "opp-microvolt", &uvolt)) + { + LOG_W("skip invalid OPP %s", rt_ofw_node_full_name(opp_np)); + continue; + } + + if (hz_nr < 2) + { + hz[1] = hz[0]; + } + if (rt_ofw_prop_read_u64(opp_np, "tcm-hz", &tcm_hz)) + { + tcm_hz = hz[0] / 2; + } + if (rt_ofw_prop_read_u64(opp_np, "ace-hz", &ace_hz)) + { + ace_hz = hz[0] / 2; + } + + if (!(opp_data = rt_calloc(1, sizeof(*opp_data)))) + { + return -RT_ENOMEM; + } + + opp_data->cluster_hz[0] = (rt_ubase_t)hz[0]; + opp_data->cluster_hz[1] = (rt_ubase_t)hz[1]; + opp_data->tcm_hz = (rt_ubase_t)tcm_hz; + opp_data->ace_hz = (rt_ubase_t)ace_hz; + + opp = rt_dvfs_scaling_add_opp(scaling, (rt_ubase_t)hz[0], uvolt); + if (!opp) + { + rt_free(opp_data); + return -RT_ENOMEM; + } + + opp->priv = opp_data; + if (!priv->is_m1 && opp->freq > SPACEMIT_K1_MAX_FREQ) + { + opp->available = RT_FALSE; + } + + if (!rt_ofw_prop_read_u32(opp_np, "clock-latency-ns", &latency) && + latency > scaling->transition_latency) + { + scaling->transition_latency = latency; + } + + ++count; + } + + if (!count) + { + return -RT_ENOENT; + } + + scaling->opp_table->share = RT_TRUE; + scaling->opp_table->priv = priv->opp_np; + + return RT_EOK; +} + +static void spacemit_free_opps(struct rt_dvfs_scaling *scaling) +{ + struct rt_dvfs_opp *opp; + + if (!scaling->opp_table) + { + return; + } + + rt_list_for_each_entry(opp, &scaling->opp_table->opp_nodes, list) + { + rt_free(opp->priv); + opp->priv = RT_NULL; + } + + rt_dvfs_scaling_remove_opp_all(scaling); + rt_free(scaling->opp_table); + scaling->opp_table = RT_NULL; +} + +static rt_err_t spacemit_get_resources(struct spacemit_cpufreq *priv) +{ + rt_err_t err; + struct rt_device *dev = &priv->pdev->parent; + + if ((err = spacemit_get_clk(priv->cpu_np, "cls0", &priv->cluster[0])) || + (err = spacemit_get_clk(priv->cpu_np, "cls1", &priv->cluster[1])) || + (err = spacemit_get_clk(priv->opp_np, "ace0", &priv->ace[0])) || + (err = spacemit_get_clk(priv->opp_np, "ace1", &priv->ace[1])) || + (err = spacemit_get_clk(priv->opp_np, "tcm", &priv->tcm)) || + (err = spacemit_get_clk(priv->opp_np, "cci", &priv->cci)) || + (err = spacemit_get_clk(priv->opp_np, "pll3", &priv->pll3)) || + (err = spacemit_get_clk(priv->opp_np, "c0hi", &priv->hi[0])) || + (err = spacemit_get_clk(priv->opp_np, "c1hi", &priv->hi[1]))) + { + return err; + } + + priv->supply = rt_regulator_get(dev, "clst"); + if (rt_is_err_or_null(priv->supply)) + { + err = priv->supply ? rt_ptr_err(priv->supply) : -RT_ENOENT; + priv->supply = RT_NULL; + LOG_E("get clst supply failed: %s", rt_strerror(err)); + return err; + } + + return RT_EOK; +} + +static void spacemit_put_resources(struct spacemit_cpufreq *priv) +{ + struct rt_clk **clks[] = + { + &priv->cluster[0], &priv->cluster[1], + &priv->ace[0], &priv->ace[1], &priv->tcm, &priv->cci, + &priv->pll3, &priv->hi[0], &priv->hi[1], + }; + + for (int i = 0; i < RT_ARRAY_SIZE(clks); ++i) + { + if (*clks[i]) + { + rt_clk_put(*clks[i]); + *clks[i] = RT_NULL; + } + } + + if (priv->supply) + { + rt_regulator_put(priv->supply); + priv->supply = RT_NULL; + } +} + +static struct rt_dvfs_opp *spacemit_closest_opp( + struct rt_dvfs_scaling *scaling, rt_ubase_t rate) +{ + rt_ubase_t best_delta = ~0UL; + struct rt_dvfs_opp *opp, *best = RT_NULL; + + rt_list_for_each_entry(opp, &scaling->opp_table->opp_nodes, list) + { + rt_ubase_t delta; + + if (!opp->available || opp->freq > scaling->max_freq) + { + continue; + } + + delta = rate_delta(rate, opp->freq); + if (!best || delta < best_delta) + { + best = opp; + best_delta = delta; + } + } + + return best; +} + +static rt_err_t spacemit_sync_hw_state(struct spacemit_cpufreq *priv, + struct rt_dvfs_scaling *scaling) +{ + rt_err_t err; + int uvolt; + rt_ubase_t rate[2], max_rate; + struct rt_dvfs_opp *opp; + struct spacemit_cpufreq_opp *opp_data; + + rate[0] = spacemit_mux_hw_rate(priv->cluster[0]); + rate[1] = spacemit_mux_hw_rate(priv->cluster[1]); + max_rate = rt_max(rate[0], rate[1]); + opp = spacemit_closest_opp(scaling, max_rate); + if (!opp) + { + return -RT_ENOENT; + } + + opp_data = opp->priv; + if (rate_matches(rate[0], opp_data->cluster_hz[0]) && + rate_matches(rate[1], opp_data->cluster_hz[1])) + { + uvolt = rt_regulator_get_voltage(priv->supply); + if (uvolt > 0 && (rt_ubase_t)uvolt < opp->uvolt) + { + if ((err = spacemit_set_voltage(priv, opp->uvolt))) + { + return err; + } + rt_dvfs_ns_sleep(scaling->transition_latency); + } + + if ((err = spacemit_finish_dependent_clks(priv, opp_data))) + { + return err; + } + + scaling->cur_freq = opp->freq; + scaling->opp_table->current_opp = opp; + return RT_EOK; + } + + LOG_W("synchronizing boot CPU clocks %lu/%lu Hz to OPP %lu Hz", + rate[0], rate[1], opp->freq); + + scaling->cur_freq = max_rate; + scaling->opp_table->current_opp = RT_NULL; + + return rt_dvfs_scaling_apply_opp(scaling, opp); +} + +static void spacemit_fill_cpu_map(struct rt_dvfs_cpufreq *cpufreq) +{ + int cpu_id = 0; + struct rt_ofw_node *cpu_np = RT_NULL; + + cpufreq->master_cpu = 0; + rt_ofw_foreach_cpu_node(cpu_np) + { + if (cpu_id < RT_CPUS_NR) + { + rt_bitmap_set_bit(cpufreq->cpus_map, cpu_id); + } + ++cpu_id; + } +} + +static void spacemit_cpufreq_destroy(struct spacemit_cpufreq *priv, + rt_bool_t scaling_registered) +{ + struct rt_dvfs_scaling *scaling; + + if (!priv) + { + return; + } + + scaling = rt_dvfs_cpufreq_to_scaling(&priv->cpufreq); + if (scaling_registered) + { + rt_dvfs_cpufreq_unregister(&priv->cpufreq); + } + + spacemit_free_opps(scaling); + spacemit_put_resources(priv); + + if (priv->lock_ready) + { + rt_mutex_detach(&priv->lock); + } + + if (priv->pdev) + { + if (priv->dev_registered) + { + rt_device_unregister(&priv->pdev->parent); + } + rt_ofw_node_put(priv->pdev->parent.ofw_node); + rt_free(priv->pdev); + } + rt_ofw_node_put(priv->opp_np); + rt_ofw_node_put(priv->cpu_np); + rt_free(priv); +} + +static int spacemit_dvfs_cpufreq_init(void) +{ + rt_err_t err; + rt_uint64_t cci_hz = SPACEMIT_DEFAULT_CCI_FREQ; + rt_ubase_t boot_freq; + struct rt_device *dev; + struct rt_ofw_node *saved_np; + struct spacemit_cpufreq *priv; + struct rt_dvfs_scaling *scaling; + + if (spacemit_cpufreq_data) + { + return RT_EOK; + } + + if (!(priv = rt_calloc(1, sizeof(*priv)))) + { + return -RT_ENOMEM; + } + + priv->cpu_np = rt_ofw_get_next_cpu_node(RT_NULL); + if (!priv->cpu_np) + { + err = -RT_ENOENT; + goto _fail; + } + + priv->opp_index = spacemit_select_opp_index(priv); + priv->opp_np = rt_ofw_parse_phandle(priv->cpu_np, "operating-points-v2", + priv->opp_index); + if (!priv->opp_np && priv->opp_index) + { + LOG_W("OPP table %u missing, falling back to table 0", priv->opp_index); + priv->opp_index = 0; + priv->opp_np = rt_ofw_parse_phandle(priv->cpu_np, + "operating-points-v2", 0); + } + if (!priv->opp_np) + { + err = -RT_ENOENT; + goto _fail; + } + + if (!(priv->pdev = rt_platform_device_alloc("cpufreq"))) + { + err = -RT_ENOMEM; + goto _fail; + } + + dev = &priv->pdev->parent; + dev->ofw_node = rt_ofw_node_get(priv->cpu_np); + rt_dm_dev_set_name_auto(dev, "cpufreq"); + + if ((err = rt_device_register(dev, rt_dm_dev_get_name(dev), + RT_DEVICE_FLAG_DEACTIVATE))) + { + goto _fail; + } + priv->dev_registered = RT_TRUE; + + if ((err = rt_mutex_init(&priv->lock, "k1-cpufreq", RT_IPC_FLAG_PRIO))) + { + goto _fail; + } + priv->lock_ready = RT_TRUE; + + if ((err = spacemit_get_resources(priv))) + { + goto _fail; + } + + scaling = rt_dvfs_cpufreq_to_scaling(&priv->cpufreq); + scaling->dev = dev; + scaling->clk = priv->cluster[0]; + scaling->supply = priv->supply; + scaling->ops = &spacemit_cpufreq_ops; + scaling->priv = priv; + scaling->transition_latency = SPACEMIT_DEFAULT_LATENCY_NS; + scaling->retry_delay = SPACEMIT_DEFAULT_RETRY_NS; + + if ((err = spacemit_parse_opps(priv, scaling))) + { + goto _fail; + } + + scaling->max_freq = priv->is_m1 ? SPACEMIT_M1_MAX_FREQ : + SPACEMIT_K1_MAX_FREQ; + boot_freq = rt_max(spacemit_mux_hw_rate(priv->cluster[0]), + spacemit_mux_hw_rate(priv->cluster[1])); + scaling->cur_freq = boot_freq; + spacemit_fill_cpu_map(&priv->cpufreq); + + rt_ofw_prop_read_u64(priv->opp_np, "cci-hz", &cci_hz); + if ((err = spacemit_set_rate(priv->cci, (rt_ubase_t)cci_hz, "cci", + SPACEMIT_FREQ_TOLERANCE))) + { + goto _fail; + } + + saved_np = dev->ofw_node; + dev->ofw_node = RT_NULL; + err = rt_dvfs_cpufreq_register(&priv->cpufreq); + dev->ofw_node = saved_np; + if (err) + { + goto _fail; + } + + if ((err = spacemit_sync_hw_state(priv, scaling))) + { + LOG_E("sync hardware state failed: %s", rt_strerror(err)); + spacemit_cpufreq_destroy(priv, RT_TRUE); + return err; + } + + if ((err = rt_dvfs_scaling_set_governor(scaling, + RT_DVFS_GOVERNOR_TYPE_ONDEMAND))) + { + LOG_W("ondemand governor unavailable: %s", rt_strerror(err)); + err = rt_dvfs_scaling_set_governor(scaling, + RT_DVFS_GOVERNOR_TYPE_PERFORMANCE); + if (err) + { + spacemit_cpufreq_destroy(priv, RT_TRUE); + return err; + } + } + + spacemit_cpufreq_data = priv; + LOG_D("CPUfreq registered as %s: %lu-%lu Hz, current %lu Hz", + rt_dm_dev_get_name(dev), scaling->min_freq, scaling->max_freq, + scaling->cur_freq); + + return RT_EOK; + +_fail: + LOG_E("CPUfreq initialization failed: %s", rt_strerror(err)); + spacemit_cpufreq_destroy(priv, RT_FALSE); + return err; +} +INIT_APP_EXPORT(spacemit_dvfs_cpufreq_init); diff --git a/bsp/spacemit/dm/ethernet/Kconfig b/bsp/spacemit/dm/ethernet/Kconfig new file mode 100644 index 000000000000..9bae7633a210 --- /dev/null +++ b/bsp/spacemit/dm/ethernet/Kconfig @@ -0,0 +1,14 @@ +config RT_ETHERNET_K1X_EMAC + bool "Spacemit K1X Ethernet MAC" + depends on RT_USING_OFW + depends on RT_USING_DMA + depends on RT_USING_PIN + depends on RT_USING_PHY_V2 + select RT_PHY_V2_REALTEK + default n + +config RT_ETHERNET_K1X_EMAC_PTP + bool "PTP clock support" + depends on RT_ETHERNET_K1X_EMAC + depends on RT_USING_PTP + default y diff --git a/bsp/spacemit/dm/ethernet/SConscript b/bsp/spacemit/dm/ethernet/SConscript new file mode 100644 index 000000000000..ebd6d2d74f14 --- /dev/null +++ b/bsp/spacemit/dm/ethernet/SConscript @@ -0,0 +1,13 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include', cwd + '/../../../../components/drivers/ethernet'] + +if GetDepend(['RT_ETHERNET_K1X_EMAC']): + src += ['eth-k1x-emac.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/ethernet/eth-k1x-emac.c b/bsp/spacemit/dm/ethernet/eth-k1x-emac.c new file mode 100644 index 000000000000..c9b8142c1866 --- /dev/null +++ b/bsp/spacemit/dm/ethernet/eth-k1x-emac.c @@ -0,0 +1,1928 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include +#include + +#ifdef RT_ETHERNET_K1X_EMAC_PTP +#include +#include +#endif +#ifdef RT_USING_SYSTEM_WORKQUEUE +#include +#endif + +#include +#include "ethernet_dm.h" + +#define DBG_TAG "ethernet.k1x" +#define DBG_LVL DBG_INFO +#include + +/* K1X APMU Ethernet control bits. */ +#define K1X_APMU_BASE_DEFAULT 0xd4282800UL +#define K1X_PHY_INTF_RGMII RT_BIT(2) +#define K1X_REF_CLK_SEL RT_BIT(3) +#define K1X_RMII_TX_CLK_SEL RT_BIT(6) +#define K1X_RMII_RX_CLK_SEL RT_BIT(7) +#define K1X_RGMII_TX_CLK_SEL RT_BIT(8) +#define K1X_AXI_SINGLE_ID RT_BIT(13) +#define K1X_RMII_TX_PHASE_SHIFT 16 +#define K1X_RMII_TX_PHASE_MASK RT_GENMASK(18, 16) +#define K1X_RMII_RX_PHASE_SHIFT 20 +#define K1X_RMII_RX_PHASE_MASK RT_GENMASK(22, 20) +#define K1X_RGMII_TX_PHASE_SHIFT 24 +#define K1X_RGMII_TX_PHASE_MASK RT_GENMASK(26, 24) +#define K1X_RGMII_RX_PHASE_SHIFT 28 +#define K1X_RGMII_RX_PHASE_MASK RT_GENMASK(30, 28) + +#define K1X_RX_DLINE_EN RT_BIT(0) +#define K1X_RX_DLINE_CODE_SHIFT 8 +#define K1X_RX_DLINE_CODE_MASK RT_GENMASK(15, 8) +#define K1X_TX_DLINE_EN RT_BIT(16) +#define K1X_TX_DLINE_CODE_SHIFT 24 +#define K1X_TX_DLINE_CODE_MASK RT_GENMASK(31, 24) + +/* DMA registers. */ +#define K1X_DMA_CONFIGURATION 0x0000 +#define K1X_DMA_CONTROL 0x0004 +#define K1X_DMA_STATUS_IRQ 0x0008 +#define K1X_DMA_INTERRUPT_ENABLE 0x000c +#define K1X_DMA_TX_AUTO_POLL_COUNTER 0x0010 +#define K1X_DMA_TX_POLL_DEMAND 0x0014 +#define K1X_DMA_RX_POLL_DEMAND 0x0018 +#define K1X_DMA_TX_BASE 0x001c +#define K1X_DMA_RX_BASE 0x0020 +#define K1X_DMA_RX_IRQ_MITIGATION 0x002c + +/* MAC registers. */ +#define K1X_MAC_GLOBAL_CONTROL 0x0100 +#define K1X_MAC_TRANSMIT_CONTROL 0x0104 +#define K1X_MAC_RECEIVE_CONTROL 0x0108 +#define K1X_MAC_ADDRESS_CONTROL 0x0118 +#define K1X_MAC_ADDRESS1_HIGH 0x0120 +#define K1X_MAC_ADDRESS1_MED 0x0124 +#define K1X_MAC_ADDRESS1_LOW 0x0128 +#define K1X_MAC_HASH_TABLE1 0x0150 +#define K1X_MAC_HASH_TABLE2 0x0154 +#define K1X_MAC_HASH_TABLE3 0x0158 +#define K1X_MAC_HASH_TABLE4 0x015c +#define K1X_MAC_FC_CONTROL 0x0160 +#define K1X_MAC_MDIO_CONTROL 0x01a0 +#define K1X_MAC_MDIO_DATA 0x01a4 +#define K1X_MAC_TX_FIFO_AF 0x01c0 +#define K1X_MAC_TX_THRESHOLD 0x01c4 +#define K1X_MAC_RX_THRESHOLD 0x01c8 +#define K1X_MAC_INTERRUPT_ENABLE 0x01e4 + +#ifdef RT_ETHERNET_K1X_EMAC_PTP +/* PTP 1588 registers. The system timer is a 17-bit fixed-point ns counter. */ +#define K1X_PTP_CONTROL 0x0300 +#define K1X_PTP_INCREMENT 0x0304 +#define K1X_PTP_ETHERTYPE 0x0308 +#define K1X_PTP_MESSAGE_ID 0x030c +#define K1X_PTP_UDP_PORT 0x0310 +#define K1X_PTP_TIME_LOW 0x0320 +#define K1X_PTP_TIME_HIGH 0x0324 +#define K1X_PTP_TX_TIME_LOW 0x0330 +#define K1X_PTP_TX_TIME_HIGH 0x0334 +#define K1X_PTP_RX_TIME_LOW 0x0340 +#define K1X_PTP_RX_TIME_HIGH 0x0344 +#define K1X_PTP_IRQ_STATUS 0x0360 +#define K1X_PTP_IRQ_ENABLE 0x0364 + +#define K1X_PTP_TX_TIMESTAMP_ENABLE RT_BIT(1) +#define K1X_PTP_RX_TIMESTAMP_ENABLE RT_BIT(2) +#define K1X_PTP_RX_TYPE_SHIFT 3 +#define K1X_PTP_RX_TYPE_MASK RT_GENMASK(5, 3) +#define K1X_PTP_RX_TYPE_V2_L2_L4 2U +#define K1X_PTP_IRQ_TX_TIMESTAMP RT_BIT(0) +#define K1X_PTP_IRQ_RX_TIMESTAMP RT_BIT(1) +#define K1X_PTP_IRQ_ALL (K1X_PTP_IRQ_TX_TIMESTAMP | \ + K1X_PTP_IRQ_RX_TIMESTAMP) + +#define K1X_PTP_INCREMENT_MASK RT_GENMASK(23, 0) +#define K1X_PTP_PERIOD_SHIFT 24 +#define K1X_PTP_INCREMENT_SHIFT 17U +#define K1X_PTP_INCREMENT_FRAC_MASK ((1ULL << K1X_PTP_INCREMENT_SHIFT) - 1) +#define K1X_PTP_DEFAULT_INCREMENT (10U << K1X_PTP_INCREMENT_SHIFT) +#define K1X_PTP_DEFAULT_PERIOD 1U +#define K1X_PTP_MAX_ADJ_PPB 1000000000L +#define K1X_PTP_NSEC_PER_SEC 1000000000ULL +#define K1X_PTP_ETHERTYPE_VALUE 0x88f7U +#define K1X_PTP_UDP_EVENT_PORT 319U +#define K1X_PTP_ALL_EVENT_MESSAGES 0x03020100U +#define K1X_PTP_OVERFLOW_POLL_MS (4U * 60U * 60U * 1000U) +#endif + +/* DMA configuration and control. */ +#define K1X_DMA_SOFT_RESET RT_BIT(0) +#define K1X_DMA_STRICT_BURST RT_BIT(17) +#define K1X_DMA_64BIT_MODE RT_BIT(18) +#define K1X_DMA_START_TX RT_BIT(0) +#define K1X_DMA_START_RX RT_BIT(1) + +/* DMA status/interrupt bits. */ +#define K1X_DMA_IRQ_TX_DONE RT_BIT(0) +#define K1X_DMA_IRQ_TX_UNAVAILABLE RT_BIT(1) +#define K1X_DMA_IRQ_TX_STOPPED RT_BIT(2) +#define K1X_DMA_IRQ_RX_DONE RT_BIT(4) +#define K1X_DMA_IRQ_RX_UNAVAILABLE RT_BIT(5) +#define K1X_DMA_IRQ_RX_STOPPED RT_BIT(6) +#define K1X_DMA_IRQ_RX_MISSED RT_BIT(7) +#define K1X_DMA_IRQ_MAC RT_BIT(8) +#define K1X_DMA_IRQ_ALL RT_GENMASK(8, 0) +#define K1X_DMA_IRQ_DEFAULT (K1X_DMA_IRQ_TX_DONE | \ + K1X_DMA_IRQ_TX_UNAVAILABLE | \ + K1X_DMA_IRQ_TX_STOPPED | \ + K1X_DMA_IRQ_RX_DONE | \ + K1X_DMA_IRQ_RX_UNAVAILABLE | \ + K1X_DMA_IRQ_RX_STOPPED | \ + K1X_DMA_IRQ_RX_MISSED) + +/* MAC control bits. */ +#define K1X_MAC_SPEED_MASK RT_GENMASK(1, 0) +#define K1X_MAC_SPEED_10 0 +#define K1X_MAC_SPEED_100 RT_BIT(0) +#define K1X_MAC_SPEED_1000 RT_BIT(1) +#define K1X_MAC_FULL_DUPLEX RT_BIT(2) +#define K1X_MAC_TX_ENABLE RT_BIT(0) +#define K1X_MAC_TX_AUTO_RETRY RT_BIT(3) +#define K1X_MAC_TX_IFG_MASK RT_GENMASK(6, 4) +#define K1X_MAC_RX_ENABLE RT_BIT(0) +#define K1X_MAC_RX_STORE_FORWARD RT_BIT(3) +#define K1X_MAC_ADDR1_ENABLE RT_BIT(0) +#define K1X_MAC_FC_DECODE_ENABLE RT_BIT(0) +#define K1X_MDIO_START RT_BIT(15) +#define K1X_MDIO_READ RT_BIT(10) + +/* RX interrupt mitigation fields. */ +#define K1X_RX_COAL_FRAMES_MASK RT_GENMASK(7, 0) +#define K1X_RX_COAL_TIMEOUT_SHIFT 8 +#define K1X_RX_COAL_TIMEOUT_MASK RT_GENMASK(27, 8) +#define K1X_RX_COAL_ENABLE RT_BIT(31) +#define K1X_AXI_CYCLES_PER_US 312U + +/* Four-word K1X DMA descriptor. */ +struct k1x_emac_desc +{ + volatile rt_uint32_t des0; + volatile rt_uint32_t des1; + volatile rt_uint32_t des2; + volatile rt_uint32_t des3; +}; + +#define K1X_DESC_OWN RT_BIT(31) +#define K1X_RX_DESC_FIRST RT_BIT(30) +#define K1X_RX_DESC_LAST RT_BIT(29) +#define K1X_DESC_END_RING RT_BIT(26) +#define K1X_DESC_BUFFER1_SIZE_MASK RT_GENMASK(11, 0) +#define K1X_TX_DESC_FIRST RT_BIT(29) +#define K1X_TX_DESC_LAST RT_BIT(30) +#define K1X_TX_DESC_IRQ RT_BIT(31) +#define K1X_RX_FRAME_LENGTH_MASK RT_GENMASK(13, 0) +#define K1X_RX_APP_STATUS_SHIFT 14 +#define K1X_RX_APP_STATUS_MASK RT_GENMASK(28, 14) +#define K1X_RX_ERR_ALIGN RT_BIT(0) +#define K1X_RX_ERR_RUNT RT_BIT(1) +#define K1X_RX_ERR_CRC RT_BIT(6) +#define K1X_RX_ERR_MAX_LEN RT_BIT(7) +#define K1X_RX_ERR_JABBER RT_BIT(8) +#define K1X_RX_ERR_LENGTH RT_BIT(9) +#define K1X_RX_ERROR_MASK (K1X_RX_ERR_ALIGN | K1X_RX_ERR_RUNT | \ + K1X_RX_ERR_CRC | K1X_RX_ERR_MAX_LEN | \ + K1X_RX_ERR_JABBER | K1X_RX_ERR_LENGTH) + +#define K1X_EMAC_BUFFER_SIZE 1536U +#define K1X_EMAC_TX_RING_DEFAULT 128U +#define K1X_EMAC_RX_RING_DEFAULT 128U +#define K1X_EMAC_RING_MIN 4U +#define K1X_EMAC_RING_MAX 128U +#define K1X_EMAC_TX_THRESHOLD_DEFAULT 192U +#define K1X_EMAC_RX_THRESHOLD_DEFAULT 12U +#define K1X_EMAC_DMA_BURST_DEFAULT 1U +#define K1X_EMAC_RX_COAL_FRAMES 64U +#define K1X_EMAC_RX_COAL_TIMEOUT_US 120U +#define K1X_EMAC_FCS_SIZE 4U +#define K1X_EMAC_LINK_POLL_MS 2000U +#define K1X_EMAC_DMA_FLAGS (RT_DMA_F_LINEAR | RT_DMA_F_32BITS | \ + RT_DMA_F_NOCACHE) + +enum k1x_clk_tuning_way +{ + K1X_CLK_TUNING_BY_REG, + K1X_CLK_TUNING_BY_DLINE, + K1X_CLK_TUNING_BY_CLK_REVERT, +}; + +struct k1x_emac +{ + struct eth_device parent; + struct rt_device *dev; + + void *base; + void *ctrl_reg; + void *dline_reg; + struct rt_clk *mac_clk; +#ifdef RT_ETHERNET_K1X_EMAC_PTP + struct rt_clk *ptp_clk; +#endif + struct rt_reset_control *rstc; + int irq; + + struct mii_bus *mii; + struct rt_phy_device *phy; + rt_phy_interface phy_interface; + struct rt_mutex mdio_lock; + rt_bool_t mdio_lock_inited; + + rt_uint8_t mac[6]; + rt_bool_t hw_ready; + rt_bool_t net_registered; + rt_bool_t irq_installed; + rt_bool_t link_up; + int speed; + int duplex; + + struct k1x_emac_desc *tx_ring; + struct k1x_emac_desc *rx_ring; + rt_uint8_t *tx_buffers; + rt_uint8_t *rx_buffers; + rt_uint32_t tx_ring_num; + rt_uint32_t rx_ring_num; + rt_uint32_t tx_head; + rt_uint32_t tx_tail; + rt_uint32_t rx_tail; + rt_ubase_t tx_ring_dma; + rt_ubase_t rx_ring_dma; + rt_ubase_t tx_buffers_dma; + rt_ubase_t rx_buffers_dma; + void *dma_blob; + rt_ubase_t dma_blob_handle; + rt_size_t dma_blob_size; + rt_sem_t tx_sem; + struct rt_mutex tx_mutex; + rt_bool_t tx_mutex_inited; + struct rt_spinlock tx_lock; + + rt_uint32_t tx_threshold; + rt_uint32_t rx_threshold; + rt_uint32_t dma_burst_len; + rt_bool_t ref_clk_from_soc; + rt_bool_t clk_tuning_enable; + enum k1x_clk_tuning_way clk_tuning_way; + rt_uint8_t tx_phase; + rt_uint8_t rx_phase; + + rt_base_t phy_reset_pin; + rt_uint8_t phy_reset_active; + rt_uint32_t phy_reset_delays[3]; + +#ifdef RT_ETHERNET_K1X_EMAC_PTP + struct rt_ptp_clock ptp_parent; + struct rt_spinlock ptp_lock; + rt_uint64_t ptp_cycle_last; + rt_uint64_t ptp_nsec; + rt_uint64_t ptp_frac; + rt_uint32_t ptp_clk_rate; + rt_uint32_t ptp_increment; + rt_bool_t ptp_supported; + rt_bool_t ptp_clk_enabled; + rt_bool_t ptp_registered; +#ifdef RT_USING_SYSTEM_WORKQUEUE + struct rt_work ptp_overflow_work; + rt_bool_t ptp_work_inited; + rt_bool_t ptp_stopping; +#endif +#endif + +#ifdef RT_USING_SYSTEM_WORKQUEUE + struct rt_work link_work; + rt_bool_t link_work_inited; + rt_bool_t stopping; +#endif +}; + +#define raw_to_k1x_emac(dev) \ + rt_container_of(dev, struct k1x_emac, parent.parent) +#ifdef RT_ETHERNET_K1X_EMAC_PTP +#define ptp_to_k1x_emac(ptp) \ + rt_container_of(ptp, struct k1x_emac, ptp_parent) +#endif + +rt_inline rt_uint32_t k1x_emac_readl(struct k1x_emac *emac, + rt_uint32_t reg) +{ + return HWREG32((rt_uint8_t *)emac->base + reg); +} + +rt_inline void k1x_emac_writel(struct k1x_emac *emac, + rt_uint32_t reg, rt_uint32_t value) +{ + HWREG32((rt_uint8_t *)emac->base + reg) = value; +} + +static rt_uint32_t k1x_emac_next(rt_uint32_t index, rt_uint32_t count) +{ + return ++index == count ? 0 : index; +} + +#ifdef RT_ETHERNET_K1X_EMAC_PTP +static rt_uint64_t k1x_emac_ptp_read_cycles(struct k1x_emac *emac) +{ + rt_uint64_t low; + rt_uint64_t high; + + /* Reading LOW first latches the matching HIGH word on K1X. */ + low = k1x_emac_readl(emac, K1X_PTP_TIME_LOW); + high = k1x_emac_readl(emac, K1X_PTP_TIME_HIGH); + + return (high << 32) | low; +} + +static rt_uint64_t k1x_emac_ptp_update_locked(struct k1x_emac *emac) +{ + rt_uint64_t now = k1x_emac_ptp_read_cycles(emac); + rt_uint64_t delta = now - emac->ptp_cycle_last; + rt_uint64_t scaled = delta + emac->ptp_frac; + + emac->ptp_frac = scaled & K1X_PTP_INCREMENT_FRAC_MASK; + emac->ptp_nsec += scaled >> K1X_PTP_INCREMENT_SHIFT; + emac->ptp_cycle_last = now; + + return emac->ptp_nsec; +} + +static rt_err_t k1x_emac_ptp_adjfreq(struct rt_ptp_clock *ptp, + rt_base_t freq) +{ + rt_bool_t negative; + rt_uint64_t magnitude; + rt_uint64_t adjustment; + rt_uint32_t increment; + rt_ubase_t level; + struct k1x_emac *emac = ptp_to_k1x_emac(ptp); + + if (freq > K1X_PTP_MAX_ADJ_PPB || freq <= -K1X_PTP_MAX_ADJ_PPB) + { + return -RT_EINVAL; + } + + negative = freq < 0; + magnitude = negative ? (rt_uint64_t)(-(rt_int64_t)freq) : + (rt_uint64_t)freq; + adjustment = (rt_uint64_t)K1X_PTP_DEFAULT_INCREMENT * magnitude / + K1X_PTP_NSEC_PER_SEC; + increment = negative ? K1X_PTP_DEFAULT_INCREMENT - adjustment : + K1X_PTP_DEFAULT_INCREMENT + adjustment; + if (!increment || increment > K1X_PTP_INCREMENT_MASK) + { + return -RT_EINVAL; + } + + level = rt_spin_lock_irqsave(&emac->ptp_lock); + k1x_emac_ptp_update_locked(emac); + k1x_emac_writel(emac, K1X_PTP_INCREMENT, + (K1X_PTP_DEFAULT_PERIOD << K1X_PTP_PERIOD_SHIFT) | + increment); + emac->ptp_increment = increment; + rt_spin_unlock_irqrestore(&emac->ptp_lock, level); + + return RT_EOK; +} + +static rt_err_t k1x_emac_ptp_adjtime(struct rt_ptp_clock *ptp, + rt_int64_t delta) +{ + rt_uint64_t magnitude; + rt_ubase_t level; + struct k1x_emac *emac = ptp_to_k1x_emac(ptp); + + level = rt_spin_lock_irqsave(&emac->ptp_lock); + k1x_emac_ptp_update_locked(emac); + + if (delta < 0) + { + magnitude = (rt_uint64_t)(-(delta + 1)) + 1; + if (magnitude > emac->ptp_nsec) + { + rt_spin_unlock_irqrestore(&emac->ptp_lock, level); + return -RT_EINVAL; + } + emac->ptp_nsec -= magnitude; + } + else + { + magnitude = (rt_uint64_t)delta; + if (magnitude > RT_UINT64_MAX - emac->ptp_nsec) + { + rt_spin_unlock_irqrestore(&emac->ptp_lock, level); + return -RT_EINVAL; + } + emac->ptp_nsec += magnitude; + } + + rt_spin_unlock_irqrestore(&emac->ptp_lock, level); + return RT_EOK; +} + +static rt_err_t k1x_emac_ptp_gettime(struct rt_ptp_clock *ptp, + struct rt_ptp_clock_time *ts) +{ + rt_uint64_t ns; + rt_ubase_t level; + struct k1x_emac *emac = ptp_to_k1x_emac(ptp); + + level = rt_spin_lock_irqsave(&emac->ptp_lock); + ns = k1x_emac_ptp_update_locked(emac); + rt_spin_unlock_irqrestore(&emac->ptp_lock, level); + + ts->sec = ns / K1X_PTP_NSEC_PER_SEC; + ts->nsec = ns % K1X_PTP_NSEC_PER_SEC; + + return RT_EOK; +} + +static rt_err_t k1x_emac_ptp_settime(struct rt_ptp_clock *ptp, + const struct rt_ptp_clock_time *ts) +{ + rt_uint64_t ns; + rt_ubase_t level; + struct k1x_emac *emac = ptp_to_k1x_emac(ptp); + + if (ts->sec < 0 || ts->nsec < 0 || + (rt_uint64_t)ts->nsec >= K1X_PTP_NSEC_PER_SEC || + (rt_uint64_t)ts->sec > + (RT_UINT64_MAX - (rt_uint64_t)ts->nsec) / + K1X_PTP_NSEC_PER_SEC) + { + return -RT_EINVAL; + } + ns = (rt_uint64_t)ts->sec * K1X_PTP_NSEC_PER_SEC + ts->nsec; + + level = rt_spin_lock_irqsave(&emac->ptp_lock); + emac->ptp_cycle_last = k1x_emac_ptp_read_cycles(emac); + emac->ptp_nsec = ns; + emac->ptp_frac = 0; + rt_spin_unlock_irqrestore(&emac->ptp_lock, level); + + return RT_EOK; +} + +static const struct rt_ptp_ops k1x_emac_ptp_ops = +{ + .adjfreq = k1x_emac_ptp_adjfreq, + .adjtime = k1x_emac_ptp_adjtime, + .gettime = k1x_emac_ptp_gettime, + .settime = k1x_emac_ptp_settime, +}; + +static void k1x_emac_ptp_hw_enable(struct k1x_emac *emac) +{ + rt_uint32_t control; + + emac->ptp_increment = K1X_PTP_DEFAULT_INCREMENT; + k1x_emac_writel(emac, K1X_PTP_INCREMENT, + (K1X_PTP_DEFAULT_PERIOD << K1X_PTP_PERIOD_SHIFT) | + emac->ptp_increment); + k1x_emac_writel(emac, K1X_PTP_MESSAGE_ID, + K1X_PTP_ALL_EVENT_MESSAGES); + k1x_emac_writel(emac, K1X_PTP_ETHERTYPE, + K1X_PTP_ETHERTYPE_VALUE); + k1x_emac_writel(emac, K1X_PTP_UDP_PORT, + K1X_PTP_UDP_EVENT_PORT); + + control = K1X_PTP_TX_TIMESTAMP_ENABLE | + K1X_PTP_RX_TIMESTAMP_ENABLE | + ((K1X_PTP_RX_TYPE_V2_L2_L4 << K1X_PTP_RX_TYPE_SHIFT) & + K1X_PTP_RX_TYPE_MASK); + k1x_emac_writel(emac, K1X_PTP_CONTROL, control); + k1x_emac_writel(emac, K1X_PTP_IRQ_STATUS, K1X_PTP_IRQ_ALL); + k1x_emac_writel(emac, K1X_PTP_IRQ_ENABLE, K1X_PTP_IRQ_ALL); + rt_hw_dsb(); +} + +static void k1x_emac_ptp_hw_disable(struct k1x_emac *emac) +{ + k1x_emac_writel(emac, K1X_PTP_IRQ_ENABLE, 0); + k1x_emac_writel(emac, K1X_PTP_CONTROL, 0); + k1x_emac_writel(emac, K1X_PTP_IRQ_STATUS, K1X_PTP_IRQ_ALL); + rt_hw_dsb(); +} + +#ifdef RT_USING_SYSTEM_WORKQUEUE +static void k1x_emac_ptp_overflow_work(struct rt_work *work, void *work_data) +{ + rt_ubase_t level; + struct k1x_emac *emac = work_data; + + RT_UNUSED(work); + + if (emac->ptp_stopping || !emac->ptp_registered) + { + return; + } + + level = rt_spin_lock_irqsave(&emac->ptp_lock); + k1x_emac_ptp_update_locked(emac); + rt_spin_unlock_irqrestore(&emac->ptp_lock, level); + + if (!emac->ptp_stopping) + { + rt_work_submit(&emac->ptp_overflow_work, + rt_tick_from_millisecond(K1X_PTP_OVERFLOW_POLL_MS)); + } +} +#endif + +static rt_err_t k1x_emac_ptp_register(struct k1x_emac *emac) +{ + rt_err_t err; + rt_uint64_t start_ns = 0; + struct timespec now; + struct rt_ptp_clock *ptp = &emac->ptp_parent; + + if (!emac->ptp_supported) + { + return RT_EOK; + } + + emac->ptp_clk = rt_clk_get_by_name(emac->dev, "ptp-clk"); + if (rt_is_err_or_null(emac->ptp_clk)) + { + LOG_E("ptp-clk is missing"); + emac->ptp_clk = RT_NULL; + return -RT_ENOSYS; + } + if ((err = rt_clk_prepare_enable(emac->ptp_clk))) + { + rt_clk_put(emac->ptp_clk); + emac->ptp_clk = RT_NULL; + return err; + } + emac->ptp_clk_enabled = RT_TRUE; + + if (!emac->ptp_clk_rate) + { + emac->ptp_clk_rate = (rt_uint32_t)rt_clk_get_rate(emac->ptp_clk); + } + + rt_spin_lock_init(&emac->ptp_lock); + k1x_emac_ptp_hw_enable(emac); + emac->ptp_cycle_last = k1x_emac_ptp_read_cycles(emac); + if (!clock_gettime(CLOCK_REALTIME, &now) && now.tv_sec >= 0 && + now.tv_nsec >= 0 && + (rt_uint64_t)now.tv_sec <= + (RT_UINT64_MAX - (rt_uint64_t)now.tv_nsec) / + K1X_PTP_NSEC_PER_SEC) + { + start_ns = (rt_uint64_t)now.tv_sec * K1X_PTP_NSEC_PER_SEC + + now.tv_nsec; + } + emac->ptp_nsec = start_ns; + emac->ptp_frac = 0; + + ptp->ops = &k1x_emac_ptp_ops; + ptp->max_freq = K1X_PTP_MAX_ADJ_PPB; + if ((err = rt_ptp_clock_register(ptp))) + { + ptp->ops = RT_NULL; + k1x_emac_ptp_hw_disable(emac); + rt_clk_disable_unprepare(emac->ptp_clk); + emac->ptp_clk_enabled = RT_FALSE; + rt_clk_put(emac->ptp_clk); + emac->ptp_clk = RT_NULL; + return err; + } + emac->ptp_registered = RT_TRUE; + +#ifdef RT_USING_SYSTEM_WORKQUEUE + rt_work_init(&emac->ptp_overflow_work, k1x_emac_ptp_overflow_work, emac); + emac->ptp_work_inited = RT_TRUE; + rt_work_submit(&emac->ptp_overflow_work, + rt_tick_from_millisecond(K1X_PTP_OVERFLOW_POLL_MS)); +#endif + + LOG_D("%s: PTP clock registered as %s, source %u Hz", + rt_dm_dev_get_name(&emac->parent.parent), + rt_dm_dev_get_name(&ptp->parent), emac->ptp_clk_rate); + return RT_EOK; +} + +static void k1x_emac_ptp_unregister(struct k1x_emac *emac) +{ +#ifdef RT_USING_SYSTEM_WORKQUEUE + emac->ptp_stopping = RT_TRUE; + if (emac->ptp_work_inited) + { + rt_work_cancel(&emac->ptp_overflow_work); + emac->ptp_work_inited = RT_FALSE; + } +#endif + + if (emac->ptp_clk_enabled) + { + k1x_emac_ptp_hw_disable(emac); + } + if (emac->ptp_registered) + { + rt_ptp_clock_unregister(&emac->ptp_parent); + emac->ptp_parent.ops = RT_NULL; + emac->ptp_registered = RT_FALSE; + } + if (emac->ptp_clk_enabled) + { + rt_clk_disable_unprepare(emac->ptp_clk); + emac->ptp_clk_enabled = RT_FALSE; + } + if (!rt_is_err_or_null(emac->ptp_clk)) + { + rt_clk_put(emac->ptp_clk); + emac->ptp_clk = RT_NULL; + } +} +#endif + +static void k1x_emac_delay_us(rt_uint32_t delay) +{ + if (delay >= 1000) + { + rt_thread_mdelay((delay + 999) / 1000); + } + else if (delay) + { + rt_hw_us_delay(delay); + } +} + +static void k1x_emac_reset_hw(struct k1x_emac *emac) +{ + k1x_emac_writel(emac, K1X_MAC_INTERRUPT_ENABLE, 0); + k1x_emac_writel(emac, K1X_DMA_INTERRUPT_ENABLE, 0); + k1x_emac_writel(emac, K1X_MAC_RECEIVE_CONTROL, 0); + k1x_emac_writel(emac, K1X_MAC_TRANSMIT_CONTROL, 0); + k1x_emac_writel(emac, K1X_DMA_CONTROL, 0); + k1x_emac_writel(emac, K1X_MAC_GLOBAL_CONTROL, 0x18); + k1x_emac_writel(emac, K1X_MAC_GLOBAL_CONTROL, 0); +} + +static rt_err_t k1x_emac_parse_phy_interface(struct k1x_emac *emac) +{ + rt_err_t err = -RT_ERROR; + struct rt_ofw_node *phy_np; + + phy_np = rt_ofw_parse_phandle(emac->dev->ofw_node, "phy-handle", 0); + if (phy_np) + { + err = rt_ofw_get_interface(phy_np, &emac->phy_interface); + rt_ofw_node_put(phy_np); + } + if (err) + { + err = rt_ofw_get_interface(emac->dev->ofw_node, + &emac->phy_interface); + } + if (err) + { + emac->phy_interface = RT_PHY_INTERFACE_MODE_RGMII; + } + + switch (emac->phy_interface) + { + case RT_PHY_INTERFACE_MODE_RMII: + case RT_PHY_INTERFACE_MODE_RGMII: + case RT_PHY_INTERFACE_MODE_RGMII_ID: + case RT_PHY_INTERFACE_MODE_RGMII_RXID: + case RT_PHY_INTERFACE_MODE_RGMII_TXID: + return RT_EOK; + default: + LOG_E("unsupported PHY interface %d", emac->phy_interface); + return -RT_EINVAL; + } +} + +static rt_err_t k1x_emac_parse_dt(struct k1x_emac *emac) +{ + struct rt_device *dev = emac->dev; + rt_uint32_t apmu_base = K1X_APMU_BASE_DEFAULT; + rt_uint32_t offset; + rt_uint32_t value; + + emac->tx_threshold = K1X_EMAC_TX_THRESHOLD_DEFAULT; + emac->rx_threshold = K1X_EMAC_RX_THRESHOLD_DEFAULT; + emac->tx_ring_num = K1X_EMAC_TX_RING_DEFAULT; + emac->rx_ring_num = K1X_EMAC_RX_RING_DEFAULT; + emac->dma_burst_len = K1X_EMAC_DMA_BURST_DEFAULT; + emac->phy_reset_pin = -1; + + rt_dm_dev_prop_read_u32(dev, "k1x,apmu-base-reg", &apmu_base); + if (rt_dm_dev_prop_read_u32(dev, "ctrl-reg", &offset)) + { + LOG_E("ctrl-reg is missing"); + return -RT_EINVAL; + } + emac->ctrl_reg = rt_ioremap((void *)(rt_ubase_t)(apmu_base + offset), 4); + if (!emac->ctrl_reg) + { + return -RT_ENOMEM; + } + + rt_dm_dev_prop_read_u32(dev, "tx-threshold", &emac->tx_threshold); + rt_dm_dev_prop_read_u32(dev, "rx-threshold", &emac->rx_threshold); + rt_dm_dev_prop_read_u32(dev, "tx-ring-num", &emac->tx_ring_num); + rt_dm_dev_prop_read_u32(dev, "rx-ring-num", &emac->rx_ring_num); + rt_dm_dev_prop_read_u32(dev, "dma-burst-len", &emac->dma_burst_len); + + if (emac->tx_ring_num < K1X_EMAC_RING_MIN) + { + LOG_D("invalid tx-ring-num %u, use %u", emac->tx_ring_num, + K1X_EMAC_TX_RING_DEFAULT); + emac->tx_ring_num = K1X_EMAC_TX_RING_DEFAULT; + } + else if (emac->tx_ring_num > K1X_EMAC_RING_MAX) + { + LOG_D("tx-ring-num %u exceeds BSP limit, clamp to %u", + emac->tx_ring_num, K1X_EMAC_RING_MAX); + emac->tx_ring_num = K1X_EMAC_RING_MAX; + } + if (emac->rx_ring_num < K1X_EMAC_RING_MIN) + { + LOG_D("invalid rx-ring-num %u, use %u", emac->rx_ring_num, + K1X_EMAC_RX_RING_DEFAULT); + emac->rx_ring_num = K1X_EMAC_RX_RING_DEFAULT; + } + else if (emac->rx_ring_num > K1X_EMAC_RING_MAX) + { + LOG_D("rx-ring-num %u exceeds BSP limit, clamp to %u", + emac->rx_ring_num, K1X_EMAC_RING_MAX); + emac->rx_ring_num = K1X_EMAC_RING_MAX; + } + if (!emac->dma_burst_len || emac->dma_burst_len > 7) + { + emac->dma_burst_len = K1X_EMAC_DMA_BURST_DEFAULT; + } + + emac->ref_clk_from_soc = + !rt_dm_dev_prop_read_bool(dev, "ref-clock-from-phy"); + emac->clk_tuning_enable = + rt_dm_dev_prop_read_bool(dev, "clk-tuning-enable"); + if (emac->clk_tuning_enable) + { + if (rt_dm_dev_prop_read_bool(dev, "clk-tuning-by-delayline")) + { + emac->clk_tuning_way = K1X_CLK_TUNING_BY_DLINE; + if (rt_dm_dev_prop_read_u32(dev, "dline-reg", &offset)) + { + LOG_E("dline-reg is missing"); + return -RT_EINVAL; + } + emac->dline_reg = rt_ioremap( + (void *)(rt_ubase_t)(apmu_base + offset), 4); + if (!emac->dline_reg) + { + return -RT_ENOMEM; + } + } + else if (rt_dm_dev_prop_read_bool(dev, "clk-tuning-by-clk-revert")) + { + emac->clk_tuning_way = K1X_CLK_TUNING_BY_CLK_REVERT; + } + else + { + emac->clk_tuning_way = K1X_CLK_TUNING_BY_REG; + } + + if (!rt_dm_dev_prop_read_u32(dev, "tx-phase", &value)) + { + emac->tx_phase = value; + } + if (!rt_dm_dev_prop_read_u32(dev, "rx-phase", &value)) + { + emac->rx_phase = value; + } + } + + emac->phy_reset_pin = rt_pin_get_named_pin(dev, "emac,reset", 0, + RT_NULL, RT_NULL); + emac->phy_reset_active = + rt_dm_dev_prop_read_bool(dev, "emac,reset-active-low") ? + PIN_LOW : PIN_HIGH; + rt_dm_dev_prop_read_u32_array_index(dev, "emac,reset-delays-us", 0, + RT_ARRAY_SIZE(emac->phy_reset_delays), + emac->phy_reset_delays); + +#ifdef RT_ETHERNET_K1X_EMAC_PTP + emac->ptp_supported = rt_dm_dev_prop_read_bool(dev, "ptp-support"); + rt_dm_dev_prop_read_u32(dev, "ptp-clk-rate", &emac->ptp_clk_rate); +#endif + + return k1x_emac_parse_phy_interface(emac); +} + +static void k1x_emac_config_interface(struct k1x_emac *emac) +{ + rt_uint32_t value = HWREG32(emac->ctrl_reg); + + if (emac->phy_interface == RT_PHY_INTERFACE_MODE_RMII) + { + value &= ~K1X_PHY_INTF_RGMII; + if (emac->ref_clk_from_soc) + { + value |= K1X_REF_CLK_SEL; + } + else + { + value &= ~K1X_REF_CLK_SEL; + } + } + else + { + value |= K1X_PHY_INTF_RGMII; + if (emac->ref_clk_from_soc) + { + value |= K1X_RGMII_TX_CLK_SEL; + } + else + { + value &= ~K1X_RGMII_TX_CLK_SEL; + } + } + value |= K1X_AXI_SINGLE_ID; + HWREG32(emac->ctrl_reg) = value; +} + +static rt_err_t k1x_emac_config_clock_phase(struct k1x_emac *emac) +{ + rt_uint32_t value; + + if (!emac->clk_tuning_enable) + { + return RT_EOK; + } + + if (emac->phy_interface == RT_PHY_INTERFACE_MODE_RMII) + { + value = HWREG32(emac->ctrl_reg); + if (emac->clk_tuning_way == K1X_CLK_TUNING_BY_CLK_REVERT) + { + value &= ~(K1X_RMII_TX_CLK_SEL | K1X_RMII_RX_CLK_SEL); + if (emac->tx_phase == 180) + { + value |= K1X_RMII_TX_CLK_SEL; + } + if (emac->rx_phase == 180) + { + value |= K1X_RMII_RX_CLK_SEL; + } + } + else if (emac->clk_tuning_way == K1X_CLK_TUNING_BY_REG) + { + value &= ~(K1X_RMII_TX_PHASE_MASK | K1X_RMII_RX_PHASE_MASK); + value |= (emac->tx_phase & 0x7) << K1X_RMII_TX_PHASE_SHIFT; + value |= (emac->rx_phase & 0x7) << K1X_RMII_RX_PHASE_SHIFT; + } + else + { + return -RT_EINVAL; + } + HWREG32(emac->ctrl_reg) = value; + } + else if (emac->clk_tuning_way == K1X_CLK_TUNING_BY_DLINE) + { + if (!emac->dline_reg) + { + return -RT_EINVAL; + } + value = HWREG32(emac->dline_reg); + value &= ~(K1X_TX_DLINE_CODE_MASK | K1X_RX_DLINE_CODE_MASK); + value |= ((rt_uint32_t)emac->tx_phase << K1X_TX_DLINE_CODE_SHIFT) & + K1X_TX_DLINE_CODE_MASK; + value |= ((rt_uint32_t)emac->rx_phase << K1X_RX_DLINE_CODE_SHIFT) & + K1X_RX_DLINE_CODE_MASK; + value |= K1X_TX_DLINE_EN | K1X_RX_DLINE_EN; + HWREG32(emac->dline_reg) = value; + } + else if (emac->clk_tuning_way == K1X_CLK_TUNING_BY_REG) + { + value = HWREG32(emac->ctrl_reg); + value &= ~(K1X_RGMII_TX_PHASE_MASK | K1X_RGMII_RX_PHASE_MASK); + value |= (emac->tx_phase & 0x7) << K1X_RGMII_TX_PHASE_SHIFT; + value |= (emac->rx_phase & 0x7) << K1X_RGMII_RX_PHASE_SHIFT; + HWREG32(emac->ctrl_reg) = value; + } + else + { + return -RT_EINVAL; + } + + return RT_EOK; +} + +static void k1x_emac_external_phy_reset(struct k1x_emac *emac) +{ + if (emac->phy_reset_pin < 0) + { + return; + } + + rt_pin_write(emac->phy_reset_pin, !emac->phy_reset_active); + rt_pin_mode(emac->phy_reset_pin, PIN_MODE_OUTPUT); + k1x_emac_delay_us(emac->phy_reset_delays[0]); + rt_pin_write(emac->phy_reset_pin, emac->phy_reset_active); + k1x_emac_delay_us(emac->phy_reset_delays[1]); + rt_pin_write(emac->phy_reset_pin, !emac->phy_reset_active); + k1x_emac_delay_us(emac->phy_reset_delays[2]); +} + +static rt_err_t k1x_emac_mdio_wait(struct k1x_emac *emac) +{ + rt_uint32_t value; + + return readl_poll_timeout((rt_uint8_t *)emac->base + K1X_MAC_MDIO_CONTROL, + value, !(value & K1X_MDIO_START), 10, 10000); +} + +static int k1x_emac_mdio_read(struct mii_bus *bus, int addr, int devad, + int reg) +{ + rt_err_t err; + rt_uint32_t command; + struct k1x_emac *emac = bus->priv; + + RT_UNUSED(devad); + + rt_mutex_take(&emac->mdio_lock, RT_WAITING_FOREVER); + err = k1x_emac_mdio_wait(emac); + if (!err) + { + command = (addr & 0x1f) | ((reg & 0x1f) << 5) | + K1X_MDIO_START | K1X_MDIO_READ; + k1x_emac_writel(emac, K1X_MAC_MDIO_DATA, 0); + k1x_emac_writel(emac, K1X_MAC_MDIO_CONTROL, command); + err = k1x_emac_mdio_wait(emac); + } + command = err ? 0 : k1x_emac_readl(emac, K1X_MAC_MDIO_DATA) & 0xffff; + rt_mutex_release(&emac->mdio_lock); + + return err ? err : (int)command; +} + +static int k1x_emac_mdio_write(struct mii_bus *bus, int addr, int devad, + int reg, rt_uint16_t value) +{ + rt_err_t err; + rt_uint32_t command; + struct k1x_emac *emac = bus->priv; + + RT_UNUSED(devad); + + rt_mutex_take(&emac->mdio_lock, RT_WAITING_FOREVER); + err = k1x_emac_mdio_wait(emac); + if (!err) + { + command = (addr & 0x1f) | ((reg & 0x1f) << 5) | K1X_MDIO_START; + k1x_emac_writel(emac, K1X_MAC_MDIO_DATA, value); + k1x_emac_writel(emac, K1X_MAC_MDIO_CONTROL, command); + err = k1x_emac_mdio_wait(emac); + } + rt_mutex_release(&emac->mdio_lock); + + return err; +} + +static int k1x_emac_find_phy_addr(struct k1x_emac *emac) +{ + struct rt_ofw_node *phy_np; + rt_uint32_t reg; + + phy_np = rt_ofw_parse_phandle(emac->dev->ofw_node, "phy-handle", 0); + if (phy_np) + { + if (!rt_ofw_prop_read_u32(phy_np, "reg", ®)) + { + rt_ofw_node_put(phy_np); + return reg; + } + rt_ofw_node_put(phy_np); + } + + for (int addr = 0; addr < 32; ++addr) + { + int id = k1x_emac_mdio_read(emac->mii, addr, + RT_MDIO_DEVAD_NONE, RT_MII_PHYSID1); + + if (id > 0 && id != 0xffff) + { + return addr; + } + } + + return -1; +} + +static rt_err_t k1x_emac_mdio_register(struct k1x_emac *emac) +{ + rt_err_t err; + int alias_id = rt_ofw_get_alias_id(emac->dev->ofw_node, "ethernet"); + + emac->mii = rt_mdio_alloc(); + if (!emac->mii) + { + return -RT_ENOMEM; + } + + emac->mii->priv = emac; + emac->mii->read = k1x_emac_mdio_read; + emac->mii->write = k1x_emac_mdio_write; + rt_snprintf(emac->mii->name, sizeof(emac->mii->name), "k1x-mdio%d", + alias_id < 0 ? 0 : alias_id); + + err = rt_mdio_register(emac->mii); + if (err) + { + rt_free(emac->mii); + emac->mii = RT_NULL; + } + + return err; +} + +static void k1x_emac_mdio_unregister(struct k1x_emac *emac) +{ + if (emac->mii) + { + rt_mdio_unregister(emac->mii); + rt_free(emac->mii); + emac->mii = RT_NULL; + } +} + +static rt_err_t k1x_emac_dma_alloc(struct k1x_emac *emac) +{ + rt_size_t tx_desc_size = sizeof(*emac->tx_ring) * emac->tx_ring_num; + rt_size_t rx_desc_size = sizeof(*emac->rx_ring) * emac->rx_ring_num; + rt_size_t tx_buf_size = K1X_EMAC_BUFFER_SIZE * emac->tx_ring_num; + rt_size_t rx_buf_size = K1X_EMAC_BUFFER_SIZE * emac->rx_ring_num; + rt_size_t rx_desc_offset = RT_ALIGN(tx_desc_size, RT_MM_PAGE_SIZE); + rt_size_t tx_buf_offset = RT_ALIGN(rx_desc_offset + rx_desc_size, + RT_MM_PAGE_SIZE); + rt_size_t rx_buf_offset = RT_ALIGN(tx_buf_offset + tx_buf_size, + RT_MM_PAGE_SIZE); + rt_ubase_t handle; + rt_uint8_t *blob; + + /* Allocates each descriptor ring independently, so both DMA ring + * bases are page aligned. Preserve that requirement in the shared pool. */ + emac->dma_blob_size = rx_buf_offset + rx_buf_size; + blob = rt_dma_alloc(emac->dev, emac->dma_blob_size, &handle, + K1X_EMAC_DMA_FLAGS); + if (!blob) + { + return -RT_ENOMEM; + } + if ((handle & RT_MM_PAGE_MASK) || handle > 0xffffffffULL || + handle + emac->dma_blob_size - 1 > 0xffffffffULL) + { + LOG_E("DMA address %#lx is not page aligned or exceeds the 32-bit aperture", + (unsigned long)handle); + rt_dma_free(emac->dev, emac->dma_blob_size, blob, handle, + K1X_EMAC_DMA_FLAGS); + return -RT_EINVAL; + } + + emac->dma_blob = blob; + emac->dma_blob_handle = handle; + emac->tx_ring = (struct k1x_emac_desc *)blob; + emac->rx_ring = (struct k1x_emac_desc *)(blob + rx_desc_offset); + emac->tx_buffers = blob + tx_buf_offset; + emac->rx_buffers = blob + rx_buf_offset; + emac->tx_ring_dma = handle; + emac->rx_ring_dma = handle + rx_desc_offset; + emac->tx_buffers_dma = handle + tx_buf_offset; + emac->rx_buffers_dma = handle + rx_buf_offset; + rt_memset(blob, 0, emac->dma_blob_size); + + return RT_EOK; +} + +static void k1x_emac_dma_free(struct k1x_emac *emac) +{ + if (emac->dma_blob) + { + rt_dma_free(emac->dev, emac->dma_blob_size, emac->dma_blob, + emac->dma_blob_handle, K1X_EMAC_DMA_FLAGS); + emac->dma_blob = RT_NULL; + } +} + +static void k1x_emac_rx_refill(struct k1x_emac *emac, rt_uint32_t index) +{ + struct k1x_emac_desc *desc = &emac->rx_ring[index]; + rt_ubase_t buffer_dma = emac->rx_buffers_dma + + index * K1X_EMAC_BUFFER_SIZE; + + desc->des0 = 0; + desc->des1 = K1X_EMAC_BUFFER_SIZE & K1X_DESC_BUFFER1_SIZE_MASK; + if (index == emac->rx_ring_num - 1) + { + desc->des1 |= K1X_DESC_END_RING; + } + desc->des2 = (rt_uint32_t)buffer_dma; + desc->des3 = 0; + rt_hw_wmb(); + desc->des0 = K1X_DESC_OWN; + rt_hw_wmb(); +} + +static rt_err_t k1x_emac_rings_init(struct k1x_emac *emac) +{ + char sem_name[RT_NAME_MAX]; + int alias_id = rt_ofw_get_alias_id(emac->dev->ofw_node, "ethernet"); + + for (rt_uint32_t i = 0; i < emac->rx_ring_num; ++i) + { + k1x_emac_rx_refill(emac, i); + } + emac->tx_head = 0; + emac->tx_tail = 0; + emac->rx_tail = 0; + + rt_snprintf(sem_name, sizeof(sem_name), "k1xtx%d", + alias_id < 0 ? 0 : alias_id); + emac->tx_sem = rt_sem_create(sem_name, emac->tx_ring_num - 1, + RT_IPC_FLAG_FIFO); + if (!emac->tx_sem) + { + return -RT_ENOMEM; + } + + rt_spin_lock_init(&emac->tx_lock); + rt_mutex_init(&emac->tx_mutex, "k1xtxm", RT_IPC_FLAG_PRIO); + emac->tx_mutex_inited = RT_TRUE; + + return RT_EOK; +} + +static void k1x_emac_rings_deinit(struct k1x_emac *emac) +{ + if (emac->tx_sem) + { + rt_sem_delete(emac->tx_sem); + emac->tx_sem = RT_NULL; + } + if (emac->tx_mutex_inited) + { + rt_mutex_detach(&emac->tx_mutex); + emac->tx_mutex_inited = RT_FALSE; + } +} + +static void k1x_emac_set_mac_address(struct k1x_emac *emac) +{ + k1x_emac_writel(emac, K1X_MAC_ADDRESS1_HIGH, + ((rt_uint32_t)emac->mac[1] << 8) | emac->mac[0]); + k1x_emac_writel(emac, K1X_MAC_ADDRESS1_MED, + ((rt_uint32_t)emac->mac[3] << 8) | emac->mac[2]); + k1x_emac_writel(emac, K1X_MAC_ADDRESS1_LOW, + ((rt_uint32_t)emac->mac[5] << 8) | emac->mac[4]); +} + +static rt_err_t k1x_emac_hw_init(struct k1x_emac *emac) +{ + rt_uint32_t value; + + k1x_emac_reset_hw(emac); + + k1x_emac_writel(emac, K1X_MAC_ADDRESS_CONTROL, + K1X_MAC_ADDR1_ENABLE); + k1x_emac_writel(emac, K1X_MAC_HASH_TABLE1, 0); + k1x_emac_writel(emac, K1X_MAC_HASH_TABLE2, 0); + k1x_emac_writel(emac, K1X_MAC_HASH_TABLE3, 0); + k1x_emac_writel(emac, K1X_MAC_HASH_TABLE4, 0); + k1x_emac_writel(emac, K1X_MAC_TX_FIFO_AF, 0x1f8); + k1x_emac_writel(emac, K1X_MAC_TX_THRESHOLD, emac->tx_threshold); + k1x_emac_writel(emac, K1X_MAC_RX_THRESHOLD, emac->rx_threshold); + k1x_emac_writel(emac, K1X_MAC_FC_CONTROL, + K1X_MAC_FC_DECODE_ENABLE); + + value = K1X_EMAC_RX_COAL_FRAMES & K1X_RX_COAL_FRAMES_MASK; + value |= ((K1X_EMAC_RX_COAL_TIMEOUT_US * K1X_AXI_CYCLES_PER_US) << + K1X_RX_COAL_TIMEOUT_SHIFT) & K1X_RX_COAL_TIMEOUT_MASK; + value |= K1X_RX_COAL_ENABLE; + k1x_emac_writel(emac, K1X_DMA_RX_IRQ_MITIGATION, value); + + k1x_emac_writel(emac, K1X_DMA_CONFIGURATION, K1X_DMA_SOFT_RESET); + rt_thread_mdelay(10); + k1x_emac_writel(emac, K1X_DMA_CONFIGURATION, 0); + rt_thread_mdelay(10); + + value = K1X_DMA_STRICT_BURST | K1X_DMA_64BIT_MODE | + RT_BIT(emac->dma_burst_len); + k1x_emac_writel(emac, K1X_DMA_CONFIGURATION, value); + k1x_emac_writel(emac, K1X_DMA_STATUS_IRQ, K1X_DMA_IRQ_ALL); + k1x_emac_set_mac_address(emac); + + k1x_emac_writel(emac, K1X_DMA_TX_BASE, + (rt_uint32_t)emac->tx_ring_dma); + k1x_emac_writel(emac, K1X_DMA_RX_BASE, + (rt_uint32_t)emac->rx_ring_dma); + + emac->hw_ready = RT_TRUE; + return RT_EOK; +} + +static void k1x_emac_hw_start(struct k1x_emac *emac) +{ + rt_uint32_t value; + + value = k1x_emac_readl(emac, K1X_MAC_TRANSMIT_CONTROL); + value &= ~K1X_MAC_TX_IFG_MASK; + value |= K1X_MAC_TX_ENABLE | K1X_MAC_TX_AUTO_RETRY; + k1x_emac_writel(emac, K1X_MAC_TRANSMIT_CONTROL, value); + k1x_emac_writel(emac, K1X_DMA_TX_AUTO_POLL_COUNTER, 0); + + value = k1x_emac_readl(emac, K1X_MAC_RECEIVE_CONTROL); + value |= K1X_MAC_RX_ENABLE | K1X_MAC_RX_STORE_FORWARD; + k1x_emac_writel(emac, K1X_MAC_RECEIVE_CONTROL, value); + + value = k1x_emac_readl(emac, K1X_DMA_CONTROL); + value |= K1X_DMA_START_TX | K1X_DMA_START_RX; + k1x_emac_writel(emac, K1X_DMA_CONTROL, value); + k1x_emac_writel(emac, K1X_DMA_RX_POLL_DEMAND, 0xff); + rt_hw_dsb(); +} + +static void k1x_emac_tx_cleanup(struct k1x_emac *emac) +{ + rt_uint32_t released = 0; + rt_ubase_t level = rt_spin_lock_irqsave(&emac->tx_lock); + + while (emac->tx_tail != emac->tx_head) + { + struct k1x_emac_desc *desc = &emac->tx_ring[emac->tx_tail]; + + rt_hw_rmb(); + if (desc->des0 & K1X_DESC_OWN) + { + break; + } + + desc->des0 = 0; + emac->tx_tail = k1x_emac_next(emac->tx_tail, emac->tx_ring_num); + ++released; + } + + rt_spin_unlock_irqrestore(&emac->tx_lock, level); + + while (released--) + { + rt_sem_release(emac->tx_sem); + } +} + +static rt_err_t k1x_emac_adjust_link(struct k1x_emac *emac) +{ + rt_uint32_t control; + + if (!emac->phy || !emac->phy->link) + { + return -RT_ERROR; + } + + control = k1x_emac_readl(emac, K1X_MAC_GLOBAL_CONTROL); + control &= ~(K1X_MAC_SPEED_MASK | K1X_MAC_FULL_DUPLEX); + + if (emac->phy->duplex == DUPLEX_FULL) + { + control |= K1X_MAC_FULL_DUPLEX; + } + switch (emac->phy->speed) + { + case SPEED_1000: + control |= K1X_MAC_SPEED_1000; + break; + case SPEED_100: + control |= K1X_MAC_SPEED_100; + break; + case SPEED_10: + control |= K1X_MAC_SPEED_10; + break; + default: + return -RT_EINVAL; + } + + k1x_emac_writel(emac, K1X_MAC_GLOBAL_CONTROL, control); + emac->speed = emac->phy->speed; + emac->duplex = emac->phy->duplex; + return RT_EOK; +} + +#ifdef RT_USING_SYSTEM_WORKQUEUE +static rt_bool_t k1x_emac_phy_poll_link(struct k1x_emac *emac) +{ + int bmsr; + + bmsr = rt_phy_read(emac->phy, RT_MDIO_DEVAD_NONE, RT_MII_BMSR); + if (bmsr < 0 || bmsr == 0xffff) + { + emac->phy->link = 0; + return RT_FALSE; + } + + /* BMSR link status is latched low, so read it again before deciding. */ + bmsr = rt_phy_read(emac->phy, RT_MDIO_DEVAD_NONE, RT_MII_BMSR); + if (bmsr < 0 || bmsr == 0xffff || !(bmsr & RT_BMSR_LSTATUS)) + { + emac->phy->link = 0; + return RT_FALSE; + } + + emac->phy->link = 1; + if (rt_genphy_parse_link(emac->phy)) + { + emac->phy->link = 0; + return RT_FALSE; + } + + return RT_TRUE; +} + +static void k1x_emac_link_work(struct rt_work *work, void *work_data) +{ + rt_bool_t link; + struct k1x_emac *emac = work_data; + + RT_UNUSED(work); + + if (emac->stopping || !emac->phy) + { + return; + } + + link = k1x_emac_phy_poll_link(emac); + + if (link) + { + if (!emac->link_up || emac->speed != emac->phy->speed || + emac->duplex != emac->phy->duplex) + { + if (!k1x_emac_adjust_link(emac)) + { + LOG_I("%s: link up, %d Mbps, %s duplex", + rt_dm_dev_get_name(&emac->parent.parent), + emac->speed, + emac->duplex == DUPLEX_FULL ? "full" : "half"); + } + } + if (!emac->link_up) + { + emac->link_up = RT_TRUE; + eth_device_linkchange(&emac->parent, RT_TRUE); + } + } + else if (emac->link_up) + { + emac->link_up = RT_FALSE; + emac->speed = 0; + emac->duplex = -1; + LOG_I("%s: link down", rt_dm_dev_get_name(&emac->parent.parent)); + eth_device_linkchange(&emac->parent, RT_FALSE); + } + + if (!emac->stopping) + { + rt_work_submit(&emac->link_work, + rt_tick_from_millisecond(K1X_EMAC_LINK_POLL_MS)); + } +} +#endif + +static rt_err_t k1x_emac_eth_tx(rt_device_t dev, struct pbuf *p) +{ + rt_err_t err = RT_EOK; + rt_uint32_t index; + rt_uint32_t next; + rt_uint32_t length; + rt_uint8_t *buffer; + struct k1x_emac_desc *desc; + struct k1x_emac *emac = raw_to_k1x_emac(dev); + + if (!emac->hw_ready || !emac->link_up || !emac->phy || + !emac->phy->link) + { + return -RT_EBUSY; + } + if (!p || !p->tot_len || p->tot_len > K1X_EMAC_BUFFER_SIZE) + { + return -RT_EINVAL; + } + + rt_mutex_take(&emac->tx_mutex, RT_WAITING_FOREVER); + k1x_emac_tx_cleanup(emac); + if (rt_sem_take(emac->tx_sem, rt_tick_from_millisecond(1000)) != RT_EOK) + { + k1x_emac_tx_cleanup(emac); + if (rt_sem_take(emac->tx_sem, 0) != RT_EOK) + { + LOG_E("%s: TX ring timeout", + rt_dm_dev_get_name(&emac->parent.parent)); + err = -RT_ETIMEOUT; + goto _out_unlock; + } + } + + index = emac->tx_head; + next = k1x_emac_next(index, emac->tx_ring_num); + desc = &emac->tx_ring[index]; + buffer = emac->tx_buffers + index * K1X_EMAC_BUFFER_SIZE; + length = p->tot_len; + pbuf_copy_partial(p, buffer, length, 0); + + desc->des0 = 0; + desc->des1 = (length & K1X_DESC_BUFFER1_SIZE_MASK) | + K1X_TX_DESC_FIRST | K1X_TX_DESC_LAST | K1X_TX_DESC_IRQ; + if (index == emac->tx_ring_num - 1) + { + desc->des1 |= K1X_DESC_END_RING; + } + desc->des2 = (rt_uint32_t)(emac->tx_buffers_dma + + index * K1X_EMAC_BUFFER_SIZE); + desc->des3 = 0; + rt_hw_wmb(); + desc->des0 = K1X_DESC_OWN; + rt_hw_wmb(); + + { + rt_ubase_t level = rt_spin_lock_irqsave(&emac->tx_lock); + emac->tx_head = next; + rt_spin_unlock_irqrestore(&emac->tx_lock, level); + } + + k1x_emac_writel(emac, K1X_DMA_TX_POLL_DEMAND, 0xff); + rt_hw_dsb(); + +_out_unlock: + rt_mutex_release(&emac->tx_mutex); + return err; +} + +static rt_bool_t k1x_emac_rx_desc_valid(rt_uint32_t des0) +{ + rt_uint32_t status = (des0 & K1X_RX_APP_STATUS_MASK) >> + K1X_RX_APP_STATUS_SHIFT; + rt_uint32_t length = des0 & K1X_RX_FRAME_LENGTH_MASK; + + if (!(des0 & K1X_RX_DESC_FIRST) || !(des0 & K1X_RX_DESC_LAST)) + { + return RT_FALSE; + } + if (status & K1X_RX_ERROR_MASK) + { + return RT_FALSE; + } + return length > K1X_EMAC_FCS_SIZE && + length <= K1X_EMAC_BUFFER_SIZE; +} + +static struct pbuf *k1x_emac_eth_rx(rt_device_t dev) +{ + struct k1x_emac *emac = raw_to_k1x_emac(dev); + + for (rt_uint32_t count = 0; count < emac->rx_ring_num; ++count) + { + rt_uint32_t index = emac->rx_tail; + struct k1x_emac_desc *desc = &emac->rx_ring[index]; + rt_uint32_t des0; + struct pbuf *p = RT_NULL; + + rt_hw_rmb(); + des0 = desc->des0; + if (des0 & K1X_DESC_OWN) + { + return RT_NULL; + } + + if (k1x_emac_rx_desc_valid(des0)) + { + rt_uint32_t length = (des0 & K1X_RX_FRAME_LENGTH_MASK) - + K1X_EMAC_FCS_SIZE; + rt_uint8_t *buffer = emac->rx_buffers + + index * K1X_EMAC_BUFFER_SIZE; + + p = pbuf_alloc(PBUF_RAW, length, PBUF_RAM); + if (p) + { + pbuf_take(p, buffer, length); + } + } + + k1x_emac_rx_refill(emac, index); + emac->rx_tail = k1x_emac_next(index, emac->rx_ring_num); + k1x_emac_writel(emac, K1X_DMA_RX_POLL_DEMAND, 0xff); + + if (p) + { + return p; + } + } + + return RT_NULL; +} + +static rt_err_t k1x_emac_eth_control(rt_device_t dev, int cmd, void *args) +{ + struct k1x_emac *emac = raw_to_k1x_emac(dev); + + switch (cmd) + { + case NIOCTL_GADDR: + if (!args) + { + return -RT_EINVAL; + } + rt_memcpy(args, emac->mac, sizeof(emac->mac)); + return RT_EOK; + default: + return -RT_EINVAL; + } +} + +static void k1x_emac_isr(int irq, void *param) +{ + rt_uint32_t status; +#ifdef RT_ETHERNET_K1X_EMAC_PTP + rt_uint32_t ptp_status = 0; +#endif + struct k1x_emac *emac = param; + + RT_UNUSED(irq); + + status = k1x_emac_readl(emac, K1X_DMA_STATUS_IRQ); + status &= K1X_DMA_IRQ_ALL; +#ifdef RT_ETHERNET_K1X_EMAC_PTP + if (emac->ptp_registered) + { + ptp_status = k1x_emac_readl(emac, K1X_PTP_IRQ_STATUS) & + K1X_PTP_IRQ_ALL; + } + if (!status && !ptp_status) +#else + if (!status) +#endif + { + return; + } + if (status) + { + k1x_emac_writel(emac, K1X_DMA_STATUS_IRQ, status); + } +#ifdef RT_ETHERNET_K1X_EMAC_PTP + if (ptp_status) + { + k1x_emac_writel(emac, K1X_PTP_IRQ_STATUS, ptp_status); + } +#endif + + if (status & (K1X_DMA_IRQ_TX_DONE | K1X_DMA_IRQ_TX_UNAVAILABLE | + K1X_DMA_IRQ_TX_STOPPED)) + { + k1x_emac_tx_cleanup(emac); + } + if (status & K1X_DMA_IRQ_RX_UNAVAILABLE) + { + k1x_emac_writel(emac, K1X_DMA_RX_POLL_DEMAND, 0xff); + } + if (emac->net_registered && + (status & (K1X_DMA_IRQ_RX_DONE | K1X_DMA_IRQ_RX_UNAVAILABLE | + K1X_DMA_IRQ_RX_STOPPED | K1X_DMA_IRQ_RX_MISSED))) + { + eth_device_ready(&emac->parent); + } +} + +#ifdef RT_USING_DEVICE_OPS +static const struct rt_device_ops k1x_emac_device_ops = +{ + .control = k1x_emac_eth_control, +}; +#endif + +static rt_err_t k1x_emac_net_register(struct k1x_emac *emac) +{ + rt_err_t err; + +#ifdef RT_USING_DEVICE_OPS + emac->parent.parent.ops = &k1x_emac_device_ops; +#else + emac->parent.parent.control = k1x_emac_eth_control; +#endif + emac->parent.eth_tx = k1x_emac_eth_tx; + emac->parent.eth_rx = k1x_emac_eth_rx; + + err = rt_dm_dev_set_name_auto(&emac->parent.parent, "e"); + if (err < 0) + { + return err; + } + + if (emac->irq >= 0) + { + rt_hw_interrupt_install(emac->irq, k1x_emac_isr, emac, + "k1x-emac"); + rt_hw_interrupt_umask(emac->irq); + emac->irq_installed = RT_TRUE; + } + + err = eth_device_init(&emac->parent, + rt_dm_dev_get_name(&emac->parent.parent)); + if (err) + { + if (emac->irq_installed) + { + rt_hw_interrupt_mask(emac->irq); + rt_pic_detach_irq(emac->irq, emac); + emac->irq_installed = RT_FALSE; + } + return err; + } + + emac->net_registered = RT_TRUE; + eth_device_linkchange(&emac->parent, RT_FALSE); + +#ifdef RT_ETHERNET_K1X_EMAC_PTP + if ((err = k1x_emac_ptp_register(emac))) + { + LOG_W("%s: PTP registration failed: %s", + rt_dm_dev_get_name(&emac->parent.parent), + rt_strerror(err)); + } +#endif + + k1x_emac_writel(emac, K1X_DMA_INTERRUPT_ENABLE, + K1X_DMA_IRQ_DEFAULT); + k1x_emac_hw_start(emac); + +#ifdef RT_USING_SYSTEM_WORKQUEUE + rt_work_init(&emac->link_work, k1x_emac_link_work, emac); + emac->link_work_inited = RT_TRUE; + rt_work_submit(&emac->link_work, 0); +#else + rt_phy_startup(emac->phy); + if (emac->phy->link && !k1x_emac_adjust_link(emac)) + { + emac->link_up = RT_TRUE; + eth_device_linkchange(&emac->parent, RT_TRUE); + } +#endif + + return RT_EOK; +} + +static void k1x_emac_net_unregister(struct k1x_emac *emac) +{ +#ifdef RT_USING_SYSTEM_WORKQUEUE + emac->stopping = RT_TRUE; + if (emac->link_work_inited) + { + rt_work_cancel(&emac->link_work); + emac->link_work_inited = RT_FALSE; + } +#endif + + k1x_emac_writel(emac, K1X_DMA_INTERRUPT_ENABLE, 0); + if (emac->irq_installed) + { + rt_hw_interrupt_mask(emac->irq); + rt_pic_detach_irq(emac->irq, emac); + emac->irq_installed = RT_FALSE; + } + if (emac->net_registered) + { + eth_device_linkchange(&emac->parent, RT_FALSE); + eth_device_deinit(&emac->parent); + emac->net_registered = RT_FALSE; + } +} + +static void k1x_emac_release(struct k1x_emac *emac) +{ + if (!emac) + { + return; + } + +#ifdef RT_ETHERNET_K1X_EMAC_PTP + k1x_emac_ptp_unregister(emac); +#endif + if (emac->base && emac->hw_ready) + { + k1x_emac_reset_hw(emac); + emac->hw_ready = RT_FALSE; + } + if (emac->phy) + { + rt_phy_shutdown(emac->phy); + emac->phy = RT_NULL; + } + k1x_emac_mdio_unregister(emac); + k1x_emac_rings_deinit(emac); + k1x_emac_dma_free(emac); + + if (emac->mdio_lock_inited) + { + rt_mutex_detach(&emac->mdio_lock); + emac->mdio_lock_inited = RT_FALSE; + } + if (!rt_is_err_or_null(emac->rstc)) + { + rt_reset_control_assert(emac->rstc); + rt_reset_control_put(emac->rstc); + } + if (!rt_is_err_or_null(emac->mac_clk)) + { + rt_clk_disable_unprepare(emac->mac_clk); + rt_clk_put(emac->mac_clk); + } + if (emac->dline_reg) + { + rt_iounmap(emac->dline_reg); + } + if (emac->ctrl_reg) + { + rt_iounmap(emac->ctrl_reg); + } + if (emac->base) + { + rt_iounmap(emac->base); + } +} + +static rt_err_t k1x_emac_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + int phy_addr; + struct rt_device *dev = &pdev->parent; + struct k1x_emac *emac = rt_calloc(1, sizeof(*emac)); + + if (!emac) + { + return -RT_ENOMEM; + } + emac->dev = dev; + emac->irq = rt_dm_dev_get_irq(dev, 0); + emac->speed = 0; + emac->duplex = -1; + + emac->base = rt_dm_dev_iomap(dev, 0); + if (!emac->base) + { + err = -RT_EIO; + goto _fail; + } + if ((err = k1x_emac_parse_dt(emac))) + { + goto _fail; + } + + emac->mac_clk = rt_clk_get_by_name(dev, "emac-clk"); + if (rt_is_err_or_null(emac->mac_clk)) + { + LOG_E("emac-clk is missing"); + err = -RT_ENOSYS; + goto _fail; + } + if ((err = rt_clk_prepare_enable(emac->mac_clk))) + { + goto _fail; + } + + emac->rstc = rt_reset_control_get_by_name(dev, "emac-reset"); + if (rt_is_err_or_null(emac->rstc)) + { + LOG_E("emac-reset is missing"); + err = -RT_ENOSYS; + goto _fail; + } + if ((err = rt_reset_control_deassert(emac->rstc))) + { + goto _fail; + } + + rt_mutex_init(&emac->mdio_lock, "k1xmdio", RT_IPC_FLAG_PRIO); + emac->mdio_lock_inited = RT_TRUE; + k1x_emac_config_interface(emac); + if ((err = k1x_emac_config_clock_phase(emac))) + { + goto _fail; + } + k1x_emac_external_phy_reset(emac); + + if ((err = k1x_emac_dma_alloc(emac))) + { + goto _fail; + } + if ((err = k1x_emac_rings_init(emac))) + { + goto _fail; + } + if ((err = k1x_emac_hw_init(emac))) + { + goto _fail; + } + if ((err = k1x_emac_mdio_register(emac))) + { + goto _fail; + } + + phy_addr = k1x_emac_find_phy_addr(emac); + if (phy_addr < 0) + { + LOG_E("no PHY found on MDIO"); + err = -RT_ENOSYS; + goto _fail; + } + LOG_D("%s: PHY attach begin at address %d", + rt_dm_dev_get_name(dev), phy_addr); + emac->phy = rt_phy_get_device(emac->mii, dev->ofw_node, phy_addr, + emac->phy_interface); + if (!emac->phy) + { + LOG_E("PHY attach failed at address %d", phy_addr); + err = -RT_ERROR; + goto _fail; + } + LOG_D("%s: PHY attach done, config begin", rt_dm_dev_get_name(dev)); + if ((err = rt_phy_config(emac->phy)) < 0) + { + LOG_E("PHY config failed: %s", rt_strerror(err)); + goto _fail; + } + LOG_D("%s: PHY config done", rt_dm_dev_get_name(dev)); + + if (rt_ofw_get_mac_addr(dev->ofw_node, emac->mac)) + { + ethernet_random_addr(&emac->parent, emac->mac); + } + k1x_emac_set_mac_address(emac); + + LOG_D("%s: network registration begin", rt_dm_dev_get_name(dev)); + if ((err = k1x_emac_net_register(emac))) + { + LOG_E("%s: network registration failed: %s", + rt_dm_dev_get_name(dev), rt_strerror(err)); + goto _fail; + } + + dev->user_data = emac; + LOG_D("%s: PHY addr %d, MAC %02x:%02x:%02x:%02x:%02x:%02x, rings %u/%u", + rt_dm_dev_get_name(&emac->parent.parent), phy_addr, + emac->mac[0], emac->mac[1], emac->mac[2], emac->mac[3], + emac->mac[4], emac->mac[5], emac->tx_ring_num, + emac->rx_ring_num); + + return RT_EOK; + +_fail: + k1x_emac_release(emac); + rt_free(emac); + return err; +} + +static rt_err_t k1x_emac_remove(struct rt_platform_device *pdev) +{ + struct k1x_emac *emac = pdev->parent.user_data; + + if (!emac) + { + return RT_EOK; + } + + pdev->parent.user_data = RT_NULL; + k1x_emac_net_unregister(emac); + k1x_emac_release(emac); + rt_free(emac); + return RT_EOK; +} + +static const struct rt_ofw_node_id k1x_emac_ofw_ids[] = +{ + { .compatible = "spacemit,k1x-emac" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver k1x_emac_driver = +{ + .name = "k1x-emac", + .ids = k1x_emac_ofw_ids, + .probe = k1x_emac_probe, + .remove = k1x_emac_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(k1x_emac_driver); diff --git a/bsp/spacemit/dm/firmware/SConscript b/bsp/spacemit/dm/firmware/SConscript new file mode 100644 index 000000000000..4cf3fd818f62 --- /dev/null +++ b/bsp/spacemit/dm/firmware/SConscript @@ -0,0 +1,12 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +src += ['firmware-spacemit.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/firmware/firmware-spacemit.c b/bsp/spacemit/dm/firmware/firmware-spacemit.c new file mode 100644 index 000000000000..14907a421f21 --- /dev/null +++ b/bsp/spacemit/dm/firmware/firmware-spacemit.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include + +#include +#include + +rt_weak rt_ubase_t spacemit_firmwares_start, spacemit_firmwares_end; + +rt_bool_t spacemit_firmware_find(const char *name, rt_ubase_t *out_base, rt_size_t *out_size) +{ + rt_ubase_t *start = &spacemit_firmwares_start, *end = &spacemit_firmwares_end; + + while (start < end) + { + if (!rt_strcmp((const char *)(*start), name)) + { + ++start; + + *out_base = *start++; + *out_size = *start++; + *out_size -= *out_base; + + return RT_TRUE; + } + + start += 3; + } + + return RT_FALSE; +} + +rt_err_t spacemit_firmware_load_elf(const char *name, rt_ubase_t phy_addr) +{ + void *vma; + rt_ubase_t base, size, load_base, seg_phys, seg_src, memsz, filesz, copy, chunk; + Elf32_Ehdr *ehdr; + Elf32_Phdr *phdr; + const rt_ubase_t MAX_IOMAP_SIZE = 128 * SIZE_MB; + + if (!spacemit_firmware_find(name, &base, &size)) + { + return -RT_EEMPTY; + } + + ehdr = (Elf32_Ehdr *)base; + + if (rt_memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0) + { + return -RT_EINVAL; + } + + if (ehdr->e_ident[EI_CLASS] != ELFCLASS32) + { + return -RT_EINVAL; + } + + if (ehdr->e_phoff == 0 || ehdr->e_phnum == 0) + { + return -RT_EINVAL; + } + + phdr = (Elf32_Phdr *)(base + ehdr->e_phoff); + load_base = phy_addr - ehdr->e_entry; + + for (int i = 0; i < ehdr->e_phnum; ++i) + { + Elf32_Phdr *p = &phdr[i]; + + if (p->p_type != PT_LOAD) + { + continue; + } + + /* Sparse remoteproc metadata (for example .resource_table) has its + * own device address and reserved-memory mapping. Relocating it with + * the executable image would write to an unrelated DDR address. */ + if (p->p_paddr > ehdr->e_entry + MAX_IOMAP_SIZE) + { + continue; + } + + if (p->p_offset + p->p_filesz > size) + { + return -RT_EINVAL; + } + + seg_phys = load_base + p->p_paddr; + seg_src = base + p->p_offset; + memsz = p->p_memsz; + filesz = p->p_filesz; + + while (memsz > 0) + { + chunk = rt_min_t(rt_ubase_t, memsz, MAX_IOMAP_SIZE); + + if (!(vma = rt_ioremap_nocache((void *)seg_phys, chunk))) + { + return -RT_ENOMEM; + } + + copy = filesz > chunk ? chunk : filesz; + + if (copy > 0) + { + rt_memcpy((void *)vma, (const void *)seg_src, copy); + seg_src += copy; + filesz -= copy; + } + + if (chunk > copy) + { + rt_memset((void *)((rt_ubase_t)vma + copy), 0, chunk - copy); + } + + rt_iounmap(vma); + + seg_phys += chunk; + memsz -= chunk; + } + } + + return RT_EOK; +} diff --git a/bsp/spacemit/dm/graphic/SConscript b/bsp/spacemit/dm/graphic/SConscript new file mode 100644 index 000000000000..3d15055d62d2 --- /dev/null +++ b/bsp/spacemit/dm/graphic/SConscript @@ -0,0 +1,13 @@ +import os +from building import * + +cwd = GetCurrentDir() +objs = [] +list = os.listdir(cwd) + +for d in list: + path = os.path.join(cwd, d) + if os.path.isfile(os.path.join(path, 'SConscript')): + objs = objs + SConscript(os.path.join(d, 'SConscript')) + +Return('objs') diff --git a/bsp/spacemit/dm/graphic/framebuffer/Kconfig b/bsp/spacemit/dm/graphic/framebuffer/Kconfig new file mode 100644 index 000000000000..4d8f8625b204 --- /dev/null +++ b/bsp/spacemit/dm/graphic/framebuffer/Kconfig @@ -0,0 +1,14 @@ +config RT_GRAPHIC_FB_SPACEMIT + bool "Spacemit K1 Saturn framebuffer" + depends on RT_USING_GRAPHIC + depends on RT_USING_OFW + depends on RT_USING_CLK + depends on RT_USING_RESET + default n + help + RT-Thread framebuffer and HDMI output drivers for the Spacemit K1 + Saturn DPU. The display clock, reset, HDMI PHY and DPU scanout are + initialized by RT-Thread without relying on a bootloader handoff. + + Supported primary-plane formats are ARGB8888, ABGR8888, RGB565 and + BGR565. HDMI currently uses the board's known-good 1920x1080p60 mode. diff --git a/bsp/spacemit/dm/graphic/framebuffer/SConscript b/bsp/spacemit/dm/graphic/framebuffer/SConscript new file mode 100644 index 000000000000..194b42d24172 --- /dev/null +++ b/bsp/spacemit/dm/graphic/framebuffer/SConscript @@ -0,0 +1,11 @@ +from building import * + +cwd = GetCurrentDir() +src = [] + +if GetDepend(['RT_GRAPHIC_FB_SPACEMIT']): + src += ['display-spacemit.c', 'hdmi-spacemit.c', 'fb-spacemit.c'] + +group = DefineGroup('DeviceDrivers', src, depend=[''], CPPPATH=[cwd]) if src else [] + +Return('group') diff --git a/bsp/spacemit/dm/graphic/framebuffer/display-spacemit.c b/bsp/spacemit/dm/graphic/framebuffer/display-spacemit.c new file mode 100644 index 000000000000..52b9ac9567ef --- /dev/null +++ b/bsp/spacemit/dm/graphic/framebuffer/display-spacemit.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include "display-spacemit.h" + +static rt_list_t spacemit_connectors = RT_LIST_OBJECT_INIT(spacemit_connectors); + +rt_err_t spacemit_display_connector_register( + struct spacemit_display_connector *connector, + struct rt_ofw_node *np, + const struct spacemit_display_connector_ops *ops, + void *priv) +{ + struct spacemit_display_connector *entry; + + if (!connector || !np || !ops || !ops->get_timing || !ops->enable) + { + return -RT_EINVAL; + } + + rt_list_for_each_entry(entry, &spacemit_connectors, list) + { + if (entry->ofw_node == np) + { + return -RT_EBUSY; + } + } + + rt_list_init(&connector->list); + connector->ofw_node = rt_ofw_node_get(np); + connector->ops = ops; + connector->priv = priv; + rt_list_insert_before(&spacemit_connectors, &connector->list); + + return RT_EOK; +} + +void spacemit_display_connector_unregister( + struct spacemit_display_connector *connector) +{ + if (!connector || !connector->ofw_node) + { + return; + } + + rt_list_remove(&connector->list); + rt_ofw_node_put(connector->ofw_node); + connector->ofw_node = RT_NULL; + connector->ops = RT_NULL; + connector->priv = RT_NULL; +} + +struct spacemit_display_connector *spacemit_display_connector_find( + const char *compatible) +{ + struct spacemit_display_connector *connector; + + if (!compatible) + { + return RT_NULL; + } + + rt_list_for_each_entry(connector, &spacemit_connectors, list) + { + if (rt_ofw_node_is_compatible(connector->ofw_node, compatible)) + { + return connector; + } + } + + return RT_NULL; +} + +static int spacemit_display_drivers_init(void) +{ + rt_err_t err; + + err = spacemit_hdmi_driver_register(); + if (err) + { + return err; + } + + return spacemit_fb_driver_register(); +} +INIT_DEVICE_EXPORT(spacemit_display_drivers_init); diff --git a/bsp/spacemit/dm/graphic/framebuffer/display-spacemit.h b/bsp/spacemit/dm/graphic/framebuffer/display-spacemit.h new file mode 100644 index 000000000000..f9eed6c5bb11 --- /dev/null +++ b/bsp/spacemit/dm/graphic/framebuffer/display-spacemit.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __DISPLAY_SPACEMIT_H__ +#define __DISPLAY_SPACEMIT_H__ + +#include +#include + +#define SPACEMIT_DISPLAY_F_PHSYNC (1U << 0) +#define SPACEMIT_DISPLAY_F_PVSYNC (1U << 1) + +struct spacemit_display_timing +{ + rt_uint32_t hactive; + rt_uint32_t vactive; + rt_uint32_t hfront_porch; + rt_uint32_t hback_porch; + rt_uint32_t hsync_len; + rt_uint32_t vfront_porch; + rt_uint32_t vback_porch; + rt_uint32_t vsync_len; + rt_uint32_t refresh; + rt_uint64_t pixelclock; + rt_uint32_t flags; +}; + +struct spacemit_display_connector; + +struct spacemit_display_connector_ops +{ + rt_err_t (*detect)(struct spacemit_display_connector *connector, + rt_bool_t *connected); + rt_err_t (*get_timing)(struct spacemit_display_connector *connector, + struct spacemit_display_timing *timing); + rt_err_t (*enable)(struct spacemit_display_connector *connector, + const struct spacemit_display_timing *timing); + rt_err_t (*disable)(struct spacemit_display_connector *connector); +}; + +struct spacemit_display_connector +{ + rt_list_t list; + struct rt_ofw_node *ofw_node; + const struct spacemit_display_connector_ops *ops; + void *priv; +}; + +rt_err_t spacemit_display_connector_register( + struct spacemit_display_connector *connector, + struct rt_ofw_node *np, + const struct spacemit_display_connector_ops *ops, + void *priv); +void spacemit_display_connector_unregister( + struct spacemit_display_connector *connector); +struct spacemit_display_connector *spacemit_display_connector_find( + const char *compatible); + +rt_err_t spacemit_hdmi_driver_register(void); +rt_err_t spacemit_fb_driver_register(void); + +#endif /* __DISPLAY_SPACEMIT_H__ */ diff --git a/bsp/spacemit/dm/graphic/framebuffer/fb-spacemit.c b/bsp/spacemit/dm/graphic/framebuffer/fb-spacemit.c new file mode 100644 index 000000000000..fa16b2fc1077 --- /dev/null +++ b/bsp/spacemit/dm/graphic/framebuffer/fb-spacemit.c @@ -0,0 +1,1135 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include +#include + +#include +#include +#include "display-spacemit.h" + +#define DBG_TAG "fb.spacemit" +#define DBG_LVL DBG_INFO +#include + +#define SPACEMIT_DPU_HDMI 0U +#define SPACEMIT_DPU_DSI 1U + +#define SPACEMIT_DPU_MAX_DIMENSION 8192U +#define SPACEMIT_DPU_HDMI_MCLK_RATE 491520000UL + +/* Saturn RDMA3, composer2 and online2 registers used by U-Boot/Linux. */ +#define SPACEMIT_DPU_CTL2_NORMAL 0x0560 +#define SPACEMIT_DPU_CTL2_CFG_READY 0x056c +#define SPACEMIT_DPU_CTL2_TIMING 0x0588 +#define SPACEMIT_DPU_CTL2_SW_START 0x058c + +#define SPACEMIT_DPU_INT_ONLINE2_MASK 0x0910 +#define SPACEMIT_DPU_INT_ONLINE2_STATUS 0x0938 +#define SPACEMIT_DPU_INT_ONLINE2_RAW 0x0960 +#define SPACEMIT_DPU_INT_VSYNC RT_BIT(0) + +#define SPACEMIT_DPU_RDMA3_LAYER_CTRL 0x0d80 +#define SPACEMIT_DPU_RDMA3_ADDR_LOW 0x0da0 +#define SPACEMIT_DPU_RDMA3_ADDR_HIGH 0x0da4 +#define SPACEMIT_DPU_RDMA3_STRIDE 0x0db8 +#define SPACEMIT_DPU_RDMA3_IMAGE_SIZE 0x0dbc +#define SPACEMIT_DPU_RDMA3_CROP_START 0x0dc0 +#define SPACEMIT_DPU_RDMA3_CROP_END 0x0dc4 +#define SPACEMIT_DPU_RDMA3_ROT_FORMAT 0x0df0 + +#define SPACEMIT_DPU_CMPS2_LAYER0 0x4c00 +#define SPACEMIT_DPU_CMPS2_HEIGHT 0x4c04 +#define SPACEMIT_DPU_CMPS2_SOLID_R 0x4c10 +#define SPACEMIT_DPU_CMPS2_SOLID_A 0x4c14 +#define SPACEMIT_DPU_CMPS2_BLEND 0x4c38 +#define SPACEMIT_DPU_CMPS2_POSITION 0x4c48 +#define SPACEMIT_DPU_CMPS2_RIGHT 0x4c4c +#define SPACEMIT_DPU_CMPS2_BOTTOM 0x4c50 +#define SPACEMIT_DPU_CMPS2_SOLID_COLOR 0x4c54 + +#define SPACEMIT_DPU_OUT2_SIZE 0x18000 +#define SPACEMIT_DPU_OUT2_CTRL4 0x18018 +#define SPACEMIT_DPU_OUT2_CTRL31 0x1807c +#define SPACEMIT_DPU_OUT2_HPORCH 0x18080 +#define SPACEMIT_DPU_OUT2_VPORCH 0x18084 +#define SPACEMIT_DPU_OUT2_SYNC 0x18088 +#define SPACEMIT_DPU_OUT2_ACTIVE_SIZE 0x1808c +#define SPACEMIT_DPU_OUT2_FORMAT 0x18090 + +#define SPACEMIT_DPU_TOP_MISC 0x0a1c + +#define SPACEMIT_DPU_RDMA3_CTRL_VALUE 0x00202040U +#define SPACEMIT_DPU_CTL2_NORMAL_VALUE 0x00040008U +#define SPACEMIT_DPU_CTL2_TIMING_VALUE 0x00000821U +#define SPACEMIT_DPU_OUT_FORMAT_RGB888 2U + +enum spacemit_dpu_rdma_format +{ + SPACEMIT_RDMA_FORMAT_ARGB8888 = 4, + SPACEMIT_RDMA_FORMAT_ABGR8888 = 5, + SPACEMIT_RDMA_FORMAT_RGB565 = 22, + SPACEMIT_RDMA_FORMAT_BGR565 = 23, +}; + +struct spacemit_fb_plane +{ + rt_ubase_t dma_handle; + rt_ubase_t dma_flags; + rt_size_t pan_offset; + rt_bool_t enabled; + rt_bool_t reserved; +}; + +struct spacemit_fb +{ + struct rt_graphic_device parent; + struct rt_device *dev; + + void *regs; + struct rt_clk_array *clks; + struct rt_reset_control *rstc; + struct spacemit_display_connector *connector; + struct spacemit_display_timing timing; + rt_bool_t clocks_enabled; + rt_bool_t connector_enabled; + rt_bool_t dpu_configured; + rt_bool_t powered; + rt_bool_t irq_attached; + rt_bool_t vsync_sem_initialized; + + rt_uint32_t output_type; + rt_uint32_t width; + rt_uint32_t height; + rt_uint32_t refresh; + rt_ubase_t reserved_fb_dma; + rt_size_t reserved_fb_size; + int irq; + struct rt_semaphore vsync_sem; + rt_atomic_t vsync_waiting; + struct rt_graphic_plane *primary; +}; + +static const rt_uint32_t spacemit_fb_modes[] = +{ + RTGRAPHIC_PIXEL_FORMAT_ARGB888, + RTGRAPHIC_PIXEL_FORMAT_ABGR888, + RTGRAPHIC_PIXEL_FORMAT_RGB565, + RTGRAPHIC_PIXEL_FORMAT_BGR565, +}; + +rt_inline rt_uint32_t spacemit_fb_readl(struct spacemit_fb *sfb, + rt_uint32_t offset) +{ + return HWREG32((rt_uint8_t *)sfb->regs + offset); +} + +rt_inline void spacemit_fb_writel(struct spacemit_fb *sfb, + rt_uint32_t offset, rt_uint32_t value) +{ + HWREG32((rt_uint8_t *)sfb->regs + offset) = value; +} + +static void spacemit_fb_isr(int irqno, void *param) +{ + struct spacemit_fb *sfb = param; + rt_uint32_t status = spacemit_fb_readl(sfb, + SPACEMIT_DPU_INT_ONLINE2_RAW); + + RT_UNUSED(irqno); + + if (status & SPACEMIT_DPU_INT_VSYNC) + { + spacemit_fb_writel(sfb, SPACEMIT_DPU_INT_ONLINE2_STATUS, + SPACEMIT_DPU_INT_VSYNC); + + if (rt_atomic_load(&sfb->vsync_waiting)) + { + rt_sem_release(&sfb->vsync_sem); + } + } +} + +static void spacemit_fb_vsync_irq_enable(struct spacemit_fb *sfb, + rt_bool_t enable) +{ + rt_uint32_t mask; + + if (!sfb->irq_attached) + { + return; + } + + mask = spacemit_fb_readl(sfb, SPACEMIT_DPU_INT_ONLINE2_MASK); + if (enable) + { + spacemit_fb_writel(sfb, SPACEMIT_DPU_INT_ONLINE2_STATUS, + SPACEMIT_DPU_INT_VSYNC); + mask |= SPACEMIT_DPU_INT_VSYNC; + } + else + { + mask &= ~SPACEMIT_DPU_INT_VSYNC; + } + spacemit_fb_writel(sfb, SPACEMIT_DPU_INT_ONLINE2_MASK, mask); +} + +static rt_err_t spacemit_fb_irq_setup(struct spacemit_fb *sfb) +{ + rt_err_t err; + + sfb->irq = rt_dm_dev_get_irq_by_name(sfb->dev, "ONLINE_IRQ"); + if (sfb->irq < 0) + { + sfb->irq = rt_dm_dev_get_irq(sfb->dev, 0); + } + if (sfb->irq < 0) + { + return sfb->irq; + } + + if ((err = rt_sem_init(&sfb->vsync_sem, "dpu-vsync", 0, + RT_IPC_FLAG_FIFO))) + { + return err; + } + sfb->vsync_sem_initialized = RT_TRUE; + rt_atomic_store(&sfb->vsync_waiting, RT_FALSE); + + rt_hw_interrupt_install(sfb->irq, spacemit_fb_isr, sfb, "dpu-online2"); + sfb->irq_attached = RT_TRUE; + + spacemit_fb_vsync_irq_enable(sfb, RT_TRUE); + rt_hw_interrupt_umask(sfb->irq); + + return RT_EOK; +} + +static void spacemit_fb_irq_cleanup(struct spacemit_fb *sfb) +{ + if (sfb->irq_attached) + { + spacemit_fb_vsync_irq_enable(sfb, RT_FALSE); + spacemit_fb_writel(sfb, SPACEMIT_DPU_INT_ONLINE2_STATUS, + SPACEMIT_DPU_INT_VSYNC); + rt_hw_interrupt_mask(sfb->irq); + rt_pic_detach_irq(sfb->irq, sfb); + sfb->irq_attached = RT_FALSE; + } + if (sfb->vsync_sem_initialized) + { + rt_sem_detach(&sfb->vsync_sem); + sfb->vsync_sem_initialized = RT_FALSE; + } +} + +static struct spacemit_fb *spacemit_fb_from_plane(struct rt_graphic_plane *plane) +{ + return rt_container_of(plane->graphic, struct spacemit_fb, parent); +} + +static struct spacemit_fb_plane *spacemit_fb_plane_priv( + struct rt_graphic_plane *plane) +{ + return (struct spacemit_fb_plane *)plane->priv; +} + +static rt_uint32_t spacemit_fb_mode_to_hw(rt_uint32_t mode) +{ + switch (mode) + { + case RTGRAPHIC_PIXEL_FORMAT_ARGB888: + return SPACEMIT_RDMA_FORMAT_ARGB8888; + case RTGRAPHIC_PIXEL_FORMAT_ABGR888: + return SPACEMIT_RDMA_FORMAT_ABGR8888; + case RTGRAPHIC_PIXEL_FORMAT_RGB565: + return SPACEMIT_RDMA_FORMAT_RGB565; + case RTGRAPHIC_PIXEL_FORMAT_BGR565: + return SPACEMIT_RDMA_FORMAT_BGR565; + default: + return RT_UINT32_MAX; + } +} + +static struct rt_ofw_node *spacemit_fb_find_display_node( + struct rt_ofw_node *port_np, rt_uint32_t output_type) +{ + const char *compatible; + struct rt_ofw_node *display_np; + + compatible = output_type == SPACEMIT_DPU_HDMI ? + "spacemit,saturn-hdmi" : "spacemit,saturn-le"; + + rt_ofw_foreach_node_by_compatible(display_np, compatible) + { + struct rt_ofw_node *ports_np = + rt_ofw_parse_phandle(display_np, "ports", 0); + rt_bool_t matched = ports_np == port_np; + + if (ports_np) + { + rt_ofw_node_put(ports_np); + } + if (matched) + { + return display_np; + } + } + + return RT_NULL; +} + +static void spacemit_fb_find_reserved_buffer(struct spacemit_fb *sfb) +{ + rt_uint64_t addr, size; + struct rt_ofw_node *rmem_np, *fb_np; + + rmem_np = rt_ofw_find_node_by_path("/reserved-memory"); + if (!rmem_np) + { + return; + } + + rt_ofw_foreach_child_node(rmem_np, fb_np) + { + if (!rt_ofw_node_tag_equ(fb_np, "framebuffer") || + rt_ofw_get_address(fb_np, 0, &addr, &size) || !size || + addr > (rt_uint64_t)(rt_ubase_t)-1 || + size > (rt_uint64_t)(rt_size_t)-1) + { + continue; + } + + sfb->reserved_fb_dma = (rt_ubase_t)addr; + sfb->reserved_fb_size = (rt_size_t)size; + rt_ofw_node_put(fb_np); + break; + } + + rt_ofw_node_put(rmem_np); +} + +static rt_err_t spacemit_fb_clocks_enable(struct spacemit_fb *sfb) +{ + rt_err_t err; + + if (sfb->clocks_enabled) + { + return RT_EOK; + } + if ((err = rt_clk_array_prepare_enable(sfb->clks))) + { + return err; + } + + if (sfb->output_type == SPACEMIT_DPU_HDMI && sfb->clks->count) + { + struct rt_clk *clk = sfb->clks->clks[0]; + + if (!rt_is_err_or_null(clk) && + (err = rt_clk_set_rate(clk, SPACEMIT_DPU_HDMI_MCLK_RATE))) + { + rt_clk_array_disable_unprepare(sfb->clks); + return err; + } + } + + sfb->clocks_enabled = RT_TRUE; + return RT_EOK; +} + +static void spacemit_fb_clocks_disable(struct spacemit_fb *sfb) +{ + if (sfb->clocks_enabled) + { + rt_clk_array_disable_unprepare(sfb->clks); + sfb->clocks_enabled = RT_FALSE; + } +} + +static void spacemit_fb_trigger(struct spacemit_fb *sfb) +{ + spacemit_fb_writel(sfb, SPACEMIT_DPU_CTL2_CFG_READY, 1); + if (!sfb->dpu_configured) + { + spacemit_fb_writel(sfb, SPACEMIT_DPU_CTL2_SW_START, 1); + } + rt_hw_dsb(); +} + +static void spacemit_fb_output_mode_set(struct spacemit_fb *sfb) +{ + const struct spacemit_display_timing *timing = &sfb->timing; + rt_uint32_t hsp = !!(timing->flags & SPACEMIT_DISPLAY_F_PHSYNC); + rt_uint32_t vsp = !!(timing->flags & SPACEMIT_DISPLAY_F_PVSYNC); + rt_uint32_t size = (timing->vactive << 16) | timing->hactive; + + spacemit_fb_writel(sfb, SPACEMIT_DPU_TOP_MISC, 0x2223); + spacemit_fb_writel(sfb, SPACEMIT_DPU_OUT2_SIZE, size); + spacemit_fb_writel(sfb, SPACEMIT_DPU_OUT2_CTRL4, 0x20); + spacemit_fb_writel(sfb, SPACEMIT_DPU_OUT2_CTRL31, 0x100); + spacemit_fb_writel(sfb, SPACEMIT_DPU_OUT2_HPORCH, + (timing->hback_porch << 16) | timing->hfront_porch); + spacemit_fb_writel(sfb, SPACEMIT_DPU_OUT2_VPORCH, + (timing->vback_porch << 16) | timing->vfront_porch); + spacemit_fb_writel(sfb, SPACEMIT_DPU_OUT2_SYNC, + (vsp << 28) | (timing->vsync_len << 16) | + (hsp << 12) | timing->hsync_len); + spacemit_fb_writel(sfb, SPACEMIT_DPU_OUT2_ACTIVE_SIZE, size); + spacemit_fb_writel(sfb, SPACEMIT_DPU_OUT2_FORMAT, + SPACEMIT_DPU_OUT_FORMAT_RGB888); +} + +static void spacemit_fb_composer_enable(struct spacemit_fb *sfb, + rt_uint32_t width, rt_uint32_t height, rt_bool_t enable) +{ + if (!enable) + { + rt_uint32_t value = spacemit_fb_readl(sfb, + SPACEMIT_DPU_CMPS2_LAYER0); + + spacemit_fb_writel(sfb, SPACEMIT_DPU_CMPS2_LAYER0, + value & ~RT_BIT(0)); + spacemit_fb_trigger(sfb); + return; + } + + spacemit_fb_writel(sfb, SPACEMIT_DPU_CMPS2_LAYER0, + (width << 8) | 1U); + spacemit_fb_writel(sfb, SPACEMIT_DPU_CMPS2_HEIGHT, height); + spacemit_fb_writel(sfb, SPACEMIT_DPU_CMPS2_SOLID_R, 0xff0000); + spacemit_fb_writel(sfb, SPACEMIT_DPU_CMPS2_SOLID_A, 0xff); + spacemit_fb_writel(sfb, SPACEMIT_DPU_CMPS2_BLEND, 0x7); + spacemit_fb_writel(sfb, SPACEMIT_DPU_CMPS2_POSITION, 0); + spacemit_fb_writel(sfb, SPACEMIT_DPU_CMPS2_RIGHT, + (width - 1U) << 16); + spacemit_fb_writel(sfb, SPACEMIT_DPU_CMPS2_BOTTOM, height - 1U); + spacemit_fb_writel(sfb, SPACEMIT_DPU_CMPS2_SOLID_COLOR, 0xff0000); +} + +static rt_err_t spacemit_fb_plane_commit(struct rt_graphic_plane *plane, + rt_bool_t enable) +{ + struct spacemit_fb *sfb = spacemit_fb_from_plane(plane); + struct spacemit_fb_plane *priv = spacemit_fb_plane_priv(plane); + rt_uint32_t hw_format; + rt_ubase_t dma; + + if (!priv) + { + return -RT_EINVAL; + } + if (!enable || !plane->framebuffer) + { + if (sfb->powered) + { + spacemit_fb_composer_enable(sfb, plane->width, plane->height, + RT_FALSE); + } + priv->enabled = RT_FALSE; + return RT_EOK; + } + if (!sfb->powered) + { + priv->enabled = RT_TRUE; + return RT_EOK; + } + + hw_format = spacemit_fb_mode_to_hw(plane->mode); + if (hw_format == RT_UINT32_MAX || !plane->width || !plane->height || + plane->line_length > 0xffffU) + { + return -RT_EINVAL; + } + + if (!sfb->dpu_configured) + { + LOG_D("initial framebuffer cache flush begin: %u bytes", + (unsigned)plane->screen_len); + } + rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, + (rt_uint8_t *)plane->framebuffer + priv->pan_offset, + plane->screen_len); + if (!sfb->dpu_configured) + { + LOG_D("initial framebuffer cache flush done"); + } + dma = priv->dma_handle + priv->pan_offset; + + if (!sfb->dpu_configured) + { + LOG_D("DPU init: fb=%p stride=%u format=%u", + dma, plane->line_length, hw_format); + } + + spacemit_fb_output_mode_set(sfb); + spacemit_fb_writel(sfb, SPACEMIT_DPU_RDMA3_LAYER_CTRL, + SPACEMIT_DPU_RDMA3_CTRL_VALUE); + spacemit_fb_writel(sfb, SPACEMIT_DPU_RDMA3_ADDR_LOW, + (rt_uint32_t)dma); + spacemit_fb_writel(sfb, SPACEMIT_DPU_RDMA3_ADDR_HIGH, + (rt_uint32_t)(dma >> 32)); + spacemit_fb_writel(sfb, SPACEMIT_DPU_RDMA3_STRIDE, + plane->line_length); + spacemit_fb_writel(sfb, SPACEMIT_DPU_RDMA3_IMAGE_SIZE, + (plane->height << 16) | plane->width); + spacemit_fb_writel(sfb, SPACEMIT_DPU_RDMA3_CROP_START, 0); + spacemit_fb_writel(sfb, SPACEMIT_DPU_RDMA3_CROP_END, + ((plane->height - 1U) << 16) | (plane->width - 1U)); + spacemit_fb_writel(sfb, SPACEMIT_DPU_RDMA3_ROT_FORMAT, hw_format); + + spacemit_fb_composer_enable(sfb, plane->width, plane->height, RT_TRUE); + spacemit_fb_writel(sfb, SPACEMIT_DPU_CTL2_NORMAL, + SPACEMIT_DPU_CTL2_NORMAL_VALUE); + spacemit_fb_writel(sfb, SPACEMIT_DPU_CTL2_TIMING, + SPACEMIT_DPU_CTL2_TIMING_VALUE); + spacemit_fb_trigger(sfb); + + priv->enabled = RT_TRUE; + if (!sfb->dpu_configured) + { + sfb->dpu_configured = RT_TRUE; + } + return RT_EOK; +} + +static void spacemit_fb_plane_free(struct rt_graphic_plane *plane) +{ + struct spacemit_fb *sfb = spacemit_fb_from_plane(plane); + struct spacemit_fb_plane *priv = spacemit_fb_plane_priv(plane); + + if (plane->framebuffer) + { + if (priv->reserved) + { + rt_iounmap(plane->framebuffer); + } + else + { + rt_dma_free(&sfb->parent.parent, plane->framebuffer_len, + plane->framebuffer, priv->dma_handle, priv->dma_flags); + } + plane->framebuffer = RT_NULL; + plane->framebuffer_len = 0; + plane->screen_len = 0; + priv->dma_handle = 0; + priv->dma_flags = 0; + priv->pan_offset = 0; + priv->reserved = RT_FALSE; + } +} + +static rt_err_t spacemit_fb_plane_flush(struct rt_graphic_plane *plane, + struct rt_device_rect_info *rect) +{ + struct spacemit_fb_plane *priv = spacemit_fb_plane_priv(plane); + rt_uint8_t *addr; + rt_size_t row, row_len, bytes_per_pixel; + + if (!plane->framebuffer || !plane->bits_per_pixel) + { + return -RT_EINVAL; + } + + if (!rect || !rect->width || !rect->height) + { + rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, + (rt_uint8_t *)plane->framebuffer + priv->pan_offset, + plane->screen_len); + return RT_EOK; + } + + if (rect->x >= plane->width || rect->y >= plane->height || + rect->width > plane->width - rect->x || + rect->height > plane->height - rect->y) + { + return -RT_EINVAL; + } + + bytes_per_pixel = plane->bits_per_pixel / 8U; + row_len = rect->width * bytes_per_pixel; + addr = (rt_uint8_t *)plane->framebuffer + priv->pan_offset + + rect->y * plane->line_length + rect->x * bytes_per_pixel; + + if (!rect->x && rect->width == plane->width) + { + rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, addr, + rect->height * plane->line_length); + return RT_EOK; + } + + for (row = 0; row < rect->height; ++row) + { + rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, addr, row_len); + addr += plane->line_length; + } + + return RT_EOK; +} + +static rt_err_t spacemit_fb_plane_update(struct rt_graphic_plane *plane, + struct rt_device_rect_info *rect) +{ + struct spacemit_fb_plane *priv = spacemit_fb_plane_priv(plane); + + if (priv->enabled) + { + return spacemit_fb_plane_flush(plane, rect); + } + + return spacemit_fb_plane_commit(plane, RT_TRUE); +} + +static rt_err_t spacemit_fb_plane_remap(struct rt_graphic_plane *plane, + rt_uint32_t mode, struct rt_device_rect_info *rect) +{ + struct spacemit_fb *sfb = spacemit_fb_from_plane(plane); + struct spacemit_fb_plane *priv = spacemit_fb_plane_priv(plane); + rt_uint32_t bpp = rt_graphic_mode_bpp(mode); + rt_size_t screen_len, fb_len; + void *framebuffer; + + if (!rect || !rect->width || !rect->height || + spacemit_fb_mode_to_hw(mode) == RT_UINT32_MAX || + (bpp != 16U && bpp != 32U)) + { + return -RT_EINVAL; + } + + if (plane->framebuffer) + { + spacemit_fb_plane_commit(plane, RT_FALSE); + } + spacemit_fb_plane_free(plane); + + plane->line_length = RT_ALIGN(rect->width * (bpp / 8U), 16U); + if (plane->line_length > 0xffffU || + rect->height > (rt_size_t)-1 / plane->line_length) + { + return -RT_EINVAL; + } + + screen_len = plane->line_length * rect->height; + if (screen_len > (rt_size_t)-1 / 2U) + { + return -RT_EINVAL; + } + fb_len = screen_len * 2U; + priv->dma_flags = RT_DMA_F_LINEAR | RT_DMA_F_32BITS; + + framebuffer = RT_NULL; + if (sfb->reserved_fb_size >= fb_len) + { + framebuffer = rt_ioremap_cached((void *)sfb->reserved_fb_dma, fb_len); + if (framebuffer) + { + priv->dma_handle = sfb->reserved_fb_dma; + priv->reserved = RT_TRUE; + LOG_D("use reserved framebuffer: va=%p dma=%p len=%u", + framebuffer, priv->dma_handle, (unsigned)fb_len); + } + else + { + LOG_D("map reserved framebuffer failed, fallback to CMA"); + } + } + + if (!framebuffer) + { + priv->dma_handle = 0; + framebuffer = rt_dma_alloc(&plane->graphic->parent, fb_len, + &priv->dma_handle, priv->dma_flags); + } + + if (!framebuffer) + { + LOG_W("double buffer allocation failed, fallback to one buffer"); + fb_len = screen_len; + + if (sfb->reserved_fb_size >= fb_len) + { + framebuffer = rt_ioremap_cached((void *)sfb->reserved_fb_dma, + fb_len); + if (framebuffer) + { + priv->dma_handle = sfb->reserved_fb_dma; + priv->reserved = RT_TRUE; + } + } + if (!framebuffer) + { + priv->dma_handle = 0; + framebuffer = rt_dma_alloc(&plane->graphic->parent, fb_len, + &priv->dma_handle, priv->dma_flags); + } + } + if (!framebuffer) + { + priv->dma_flags = 0; + return -RT_ENOMEM; + } + + rt_memset(framebuffer, 0, fb_len); + + plane->framebuffer = framebuffer; + plane->framebuffer_len = fb_len; + plane->screen_len = screen_len; + plane->bits_per_pixel = bpp; + plane->mode = mode; + plane->width = rect->width; + plane->height = rect->height; + plane->x = 0; + plane->y = 0; + priv->pan_offset = 0; + + return spacemit_fb_plane_commit(plane, RT_TRUE); +} + +static rt_err_t spacemit_fb_plane_pan_display(struct rt_graphic_plane *plane, + struct rt_device_rect_info *rect) +{ + struct spacemit_fb_plane *priv = spacemit_fb_plane_priv(plane); + rt_size_t offset; + + if (!rect) + { + return -RT_EINVAL; + } + if (rect->width != plane->width || rect->height != plane->height) + { + return spacemit_fb_plane_remap(plane, plane->mode, rect); + } + + offset = rect->y * plane->line_length + + rect->x * (plane->bits_per_pixel / 8U); + if (offset + plane->screen_len > plane->framebuffer_len) + { + return -RT_EINVAL; + } + + if (offset == priv->pan_offset && priv->enabled) + { + return RT_EOK; + } + + priv->pan_offset = offset; + plane->x = rect->x; + plane->y = rect->y; + + return spacemit_fb_plane_commit(plane, RT_TRUE); +} + +static rt_err_t spacemit_fb_plane_cleanup(struct rt_graphic_plane *plane) +{ + struct spacemit_fb_plane *priv = spacemit_fb_plane_priv(plane); + + if (priv->enabled) + { + spacemit_fb_plane_commit(plane, RT_FALSE); + } + spacemit_fb_plane_free(plane); + + return RT_EOK; +} + +static const struct rt_graphic_plane_ops spacemit_fb_plane_ops = +{ + .update = spacemit_fb_plane_update, + .fb_remap = spacemit_fb_plane_remap, + .fb_pan_display = spacemit_fb_plane_pan_display, + .fb_cleanup = spacemit_fb_plane_cleanup, +}; + +static rt_err_t spacemit_fb_dpms_switch(struct rt_graphic_device *gdev, + rt_uint32_t dpms) +{ + rt_err_t err; + struct spacemit_fb *sfb = rt_container_of(gdev, struct spacemit_fb, parent); + + switch (dpms) + { + case RT_GRAPHIC_DPMS_ON: + if ((err = spacemit_fb_clocks_enable(sfb))) + { + return err; + } + + if ((err = rt_reset_control_deassert(sfb->rstc))) + { + spacemit_fb_clocks_disable(sfb); + return err; + } + rt_hw_us_delay(10); + spacemit_fb_vsync_irq_enable(sfb, RT_TRUE); + + if (!sfb->connector_enabled) + { + err = sfb->connector->ops->enable(sfb->connector, &sfb->timing); + if (err) + { + rt_reset_control_assert(sfb->rstc); + spacemit_fb_clocks_disable(sfb); + return err; + } + sfb->connector_enabled = RT_TRUE; + } + + sfb->powered = RT_TRUE; + if (sfb->primary && sfb->primary->framebuffer && + !spacemit_fb_plane_priv(sfb->primary)->enabled) + { + sfb->dpu_configured = RT_FALSE; + if ((err = spacemit_fb_plane_commit(sfb->primary, RT_TRUE))) + { + return err; + } + } + break; + + case RT_GRAPHIC_DPMS_STANDBY: + case RT_GRAPHIC_DPMS_SUSPEND: + if (sfb->primary) + { + spacemit_fb_plane_commit(sfb->primary, RT_FALSE); + } + break; + + case RT_GRAPHIC_DPMS_OFF: + if (sfb->primary) + { + spacemit_fb_plane_commit(sfb->primary, RT_FALSE); + } + + if (sfb->connector_enabled && sfb->connector->ops->disable) + { + sfb->connector->ops->disable(sfb->connector); + sfb->connector_enabled = RT_FALSE; + } + + spacemit_fb_vsync_irq_enable(sfb, RT_FALSE); + rt_reset_control_assert(sfb->rstc); + sfb->powered = RT_FALSE; + sfb->dpu_configured = RT_FALSE; + spacemit_fb_clocks_disable(sfb); + break; + + default: + return -RT_EINVAL; + } + + gdev->dpms = dpms; + return RT_EOK; +} + +static rt_err_t spacemit_fb_wait_vsync(struct rt_graphic_device *gdev) +{ + struct spacemit_fb *sfb = rt_container_of(gdev, struct spacemit_fb, parent); + rt_uint32_t timeout_ms; + rt_err_t err; + + if (!sfb->powered || !sfb->irq_attached) + { + return -RT_EIO; + } + + while (rt_sem_take(&sfb->vsync_sem, 0) == RT_EOK) + { + } + + rt_atomic_store(&sfb->vsync_waiting, RT_TRUE); + timeout_ms = rt_max(50U, (3000U + sfb->refresh - 1U) / sfb->refresh); + err = rt_sem_take(&sfb->vsync_sem, + rt_tick_from_millisecond(timeout_ms)); + rt_atomic_store(&sfb->vsync_waiting, RT_FALSE); + + if (err) + { + LOG_W("wait for VSYNC timed out: raw=0x%08x mask=0x%08x", + spacemit_fb_readl(sfb, SPACEMIT_DPU_INT_ONLINE2_RAW), + spacemit_fb_readl(sfb, SPACEMIT_DPU_INT_ONLINE2_MASK)); + } + + return err; +} + +static const struct rt_graphic_device_ops spacemit_fb_ops = +{ + .dpms_switch = spacemit_fb_dpms_switch, + .wait_vsync = spacemit_fb_wait_vsync, +}; + +static rt_err_t spacemit_fb_plane_create(struct spacemit_fb *sfb) +{ + rt_err_t err; + struct rt_graphic_plane *plane; + + plane = rt_graphic_device_alloc_plane(&sfb->parent, + sizeof(struct spacemit_fb_plane), &spacemit_fb_plane_ops, + spacemit_fb_modes, RT_ARRAY_SIZE(spacemit_fb_modes), + RT_GRAPHIC_PLANE_TYPE_PRIMARY); + if (!plane) + { + return -RT_ENOMEM; + } + if ((err = rt_graphic_device_add_plane(&sfb->parent, plane))) + { + rt_graphic_device_free_plane(plane); + return err; + } + + plane->mode = RTGRAPHIC_PIXEL_FORMAT_ARGB888; + plane->bits_per_pixel = 32; + /* Let graphic registration allocate the initial buffer from EDID size. */ + plane->width = 0; + plane->height = 0; + plane->alpha = 0xff; + sfb->primary = plane; + + return RT_EOK; +} + +static rt_err_t spacemit_fb_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + const char *connector_compatible; + struct rt_ofw_node *display_np; + struct rt_device *dev = &pdev->parent; + struct spacemit_fb *sfb = rt_calloc(1, sizeof(*sfb)); + + if (!sfb) + { + return -RT_ENOMEM; + } + + sfb->dev = dev; + if (rt_dm_dev_prop_read_u32(dev, "type", &sfb->output_type) || + sfb->output_type > SPACEMIT_DPU_DSI) + { + err = -RT_EINVAL; + goto _fail; + } + + display_np = spacemit_fb_find_display_node(dev->ofw_node, + sfb->output_type); + if (!display_np) + { + LOG_E("cannot find Saturn register node for %s", + rt_ofw_node_full_name(dev->ofw_node)); + err = -RT_ENOENT; + goto _fail; + } + + sfb->regs = rt_ofw_iomap(display_np, 0); + rt_ofw_node_put(display_np); + if (!sfb->regs) + { + err = -RT_EIO; + goto _fail; + } + + sfb->clks = rt_clk_get_array(dev); + if (rt_is_err(sfb->clks)) + { + err = rt_ptr_err(sfb->clks); + sfb->clks = RT_NULL; + goto _fail_unmap; + } + if ((err = spacemit_fb_clocks_enable(sfb))) + { + goto _fail_clks; + } + + sfb->rstc = rt_reset_control_get_by_name(dev, "hdmi_reset"); + if (rt_is_err(sfb->rstc)) + { + err = rt_ptr_err(sfb->rstc); + sfb->rstc = RT_NULL; + LOG_E("get DPU reset failed: %s", rt_strerror(err)); + goto _fail_power; + } + + if ((err = rt_reset_control_assert(sfb->rstc))) + { + LOG_E("assert DPU reset failed: %s", rt_strerror(err)); + goto _fail_reset; + } + rt_hw_us_delay(10); + if ((err = rt_reset_control_deassert(sfb->rstc))) + { + LOG_E("deassert DPU reset failed: %s", rt_strerror(err)); + goto _fail_reset; + } + rt_hw_us_delay(10); + + connector_compatible = sfb->output_type == SPACEMIT_DPU_HDMI ? + "spacemit,hdmi" : "spacemit,dsi2-host"; + sfb->connector = spacemit_display_connector_find(connector_compatible); + if (!sfb->connector) + { + LOG_E("no enabled %s connector found", connector_compatible); + err = -RT_ENOENT; + goto _fail_reset; + } + + if ((err = sfb->connector->ops->get_timing(sfb->connector, + &sfb->timing))) + { + LOG_E("get connector timing failed: %s", rt_strerror(err)); + goto _fail_reset; + } + + sfb->width = sfb->timing.hactive; + sfb->height = sfb->timing.vactive; + sfb->refresh = sfb->timing.refresh; + if (!sfb->width || !sfb->height || !sfb->refresh || + !sfb->timing.pixelclock || !sfb->timing.hsync_len || + !sfb->timing.vsync_len || + sfb->width > SPACEMIT_DPU_MAX_DIMENSION || + sfb->height > SPACEMIT_DPU_MAX_DIMENSION) + { + err = -RT_EINVAL; + goto _fail_reset; + } + + if ((err = sfb->connector->ops->enable(sfb->connector, &sfb->timing))) + { + LOG_E("connector cold init failed: %s", rt_strerror(err)); + goto _fail_reset; + } + sfb->connector_enabled = RT_TRUE; + sfb->powered = RT_TRUE; + + if ((err = spacemit_fb_irq_setup(sfb))) + { + LOG_E("setup DPU VSYNC interrupt failed: %s", rt_strerror(err)); + goto _fail_connector; + } + + spacemit_fb_find_reserved_buffer(sfb); + if (!sfb->reserved_fb_size) + { + LOG_W("no reserved framebuffer found, initial scanout uses CMA"); + } + + sfb->parent.ops = &spacemit_fb_ops; + if ((err = spacemit_fb_plane_create(sfb))) + { + goto _fail_connector; + } + + if ((err = rt_graphic_device_simple_edid(&sfb->parent, sfb->width, + sfb->height, sfb->refresh))) + { + rt_graphic_device_del_plane(&sfb->parent, sfb->primary); + rt_graphic_device_free_plane(sfb->primary); + sfb->primary = RT_NULL; + goto _fail_connector; + } + if ((err = rt_graphic_device_register(&sfb->parent))) + { + rt_graphic_device_del_plane(&sfb->parent, sfb->primary); + rt_graphic_device_free_plane(sfb->primary); + sfb->primary = RT_NULL; + goto _fail_connector; + } + + if ((err = spacemit_fb_dpms_switch(&sfb->parent, RT_GRAPHIC_DPMS_ON))) + { + rt_graphic_device_unregister(&sfb->parent); + sfb->primary = RT_NULL; + goto _fail_connector; + } + pdev->parent.user_data = sfb; + + LOG_D("%s framebuffer fb%u: %ux%u@%u", + sfb->output_type == SPACEMIT_DPU_HDMI ? "HDMI" : "DSI", + sfb->parent.parent.device_id, sfb->width, sfb->height, + sfb->refresh); + + return RT_EOK; + +_fail_connector: + spacemit_fb_irq_cleanup(sfb); + if (sfb->connector_enabled && sfb->connector->ops->disable) + { + sfb->connector->ops->disable(sfb->connector); + sfb->connector_enabled = RT_FALSE; + } + sfb->powered = RT_FALSE; +_fail_reset: + if (sfb->rstc) + { + rt_reset_control_assert(sfb->rstc); + rt_reset_control_put(sfb->rstc); + } +_fail_power: + spacemit_fb_clocks_disable(sfb); +_fail_clks: + if (sfb->clks) + { + rt_clk_array_put(sfb->clks); + } +_fail_unmap: + rt_iounmap(sfb->regs); +_fail: + rt_free(sfb); + return err; +} + +static rt_err_t spacemit_fb_remove(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct spacemit_fb *sfb = pdev->parent.user_data; + + if (!sfb) + { + return RT_EOK; + } + + if ((err = rt_graphic_device_unregister(&sfb->parent))) + { + return err; + } + sfb->primary = RT_NULL; + spacemit_fb_irq_cleanup(sfb); + if (sfb->rstc) + { + rt_reset_control_put(sfb->rstc); + } + if (sfb->clks) + { + rt_clk_array_put(sfb->clks); + } + rt_iounmap(sfb->regs); + rt_free(sfb); + pdev->parent.user_data = RT_NULL; + + return RT_EOK; +} + +static const struct rt_ofw_node_id spacemit_fb_ids[] = +{ + { .compatible = "spacemit,dpu-online2" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_fb_driver = +{ + .name = "spacemit-framebuffer", + .ids = spacemit_fb_ids, + .probe = spacemit_fb_probe, + .remove = spacemit_fb_remove, +}; + +rt_err_t spacemit_fb_driver_register(void) +{ + return rt_platform_driver_register(&spacemit_fb_driver); +} diff --git a/bsp/spacemit/dm/graphic/framebuffer/hdmi-spacemit.c b/bsp/spacemit/dm/graphic/framebuffer/hdmi-spacemit.c new file mode 100644 index 000000000000..4708e198b6a2 --- /dev/null +++ b/bsp/spacemit/dm/graphic/framebuffer/hdmi-spacemit.c @@ -0,0 +1,482 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include +#include + +#include "display-spacemit.h" + +#define DBG_TAG "hdmi.spacemit" +#define DBG_LVL DBG_INFO +#include + +#define SPACEMIT_HDMI_MCLK_RATE 491520000UL +#define SPACEMIT_HDMI_PHY_STATUS 0x000c +#define SPACEMIT_HDMI_PHY_HPD RT_BIT(12) +#define SPACEMIT_HDMI_PHY_CTRL 0x0028 +#define SPACEMIT_HDMI_COLOR_DEPTH 0x0034 +#define SPACEMIT_HDMI_PHY_ANALOG 0x00e0 +#define SPACEMIT_HDMI_PLL_CTRL 0x00e4 +#define SPACEMIT_HDMI_PLL_FRAC 0x00e8 +#define SPACEMIT_HDMI_PLL_DIV 0x00ec +#define SPACEMIT_HDMI_PLL_POST 0x00f0 + +#define SPACEMIT_HDMI_EIGHT_BPP 0U + +struct spacemit_hdmi +{ + struct rt_device *dev; + void *regs; + struct rt_clk *mclk; + struct rt_reset_control *rstc; + struct spacemit_display_connector connector; + rt_bool_t prepared; + rt_bool_t enabled; +}; + +static const struct spacemit_display_timing spacemit_hdmi_1080p60 = +{ + .hactive = 1920, + .vactive = 1080, + .hfront_porch = 88, + .hback_porch = 148, + .hsync_len = 44, + .vfront_porch = 4, + .vback_porch = 36, + .vsync_len = 5, + .refresh = 60, + .pixelclock = 148500000ULL, + .flags = SPACEMIT_DISPLAY_F_PHSYNC | SPACEMIT_DISPLAY_F_PVSYNC, +}; + +rt_inline rt_uint32_t spacemit_hdmi_readl(struct spacemit_hdmi *hdmi, + rt_uint32_t offset) +{ + return HWREG32((rt_uint8_t *)hdmi->regs + offset); +} + +rt_inline void spacemit_hdmi_writel(struct spacemit_hdmi *hdmi, + rt_uint32_t offset, rt_uint32_t value) +{ + HWREG32((rt_uint8_t *)hdmi->regs + offset) = value; +} + +static void spacemit_hdmi_update_bits(struct spacemit_hdmi *hdmi, + rt_uint32_t offset, rt_uint32_t mask, rt_uint32_t value) +{ + rt_uint32_t reg = spacemit_hdmi_readl(hdmi, offset); + + reg &= ~mask; + reg |= value & mask; + spacemit_hdmi_writel(hdmi, offset, reg); +} + +static int spacemit_hdmi_pll8(rt_uint32_t bit_clock_khz) +{ + bit_clock_khz /= 100U; + + if (bit_clock_khz < 425U) + { + return 3; + } + if (bit_clock_khz < 850U) + { + return 2; + } + if (bit_clock_khz < 1700U) + { + return 1; + } + + return 0; +} + +static int spacemit_hdmi_pll6(rt_uint32_t bit_clock_khz) +{ + bit_clock_khz /= 100U; + + if (bit_clock_khz <= 337U) + { + return 0; + } + if (bit_clock_khz < 425U) + { + return 1; + } + if (bit_clock_khz < 675U) + { + return 0; + } + if (bit_clock_khz < 850U) + { + return 1; + } + if (bit_clock_khz < 1350U) + { + return 0; + } + if (bit_clock_khz < 1700U) + { + return 1; + } + + return 0; +} + +static int spacemit_hdmi_pll5(rt_uint32_t bit_clock_khz) +{ + rt_uint32_t value = bit_clock_khz * + (1U << spacemit_hdmi_pll8(bit_clock_khz)) / 100U; + + if (value < 1830U) + { + return 0; + } + if (value < 2030U) + { + return 1; + } + if (value < 2275U) + { + return 2; + } + if (value < 2520U) + { + return 3; + } + if (value < 2765U) + { + return 4; + } + if (value < 3015U) + { + return 5; + } + if (value < 3260U) + { + return 6; + } + + return 7; +} + +static void spacemit_hdmi_pll_fraction(rt_uint32_t bit_clock_khz, + int *integer_part, rt_uint32_t *frac_reg) +{ + const rt_int64_t scale = 1000000000LL; + const int pll8 = spacemit_hdmi_pll8(bit_clock_khz); + const int pll6 = spacemit_hdmi_pll6(bit_clock_khz); + const rt_int64_t numerator = + (rt_int64_t)(1U << pll8) * bit_clock_khz; + const rt_int64_t denominator = 100LL * (pll6 + 1) * 24LL; + rt_int64_t value = numerator * scale / denominator; + rt_int64_t integer = numerator / denominator * scale; + rt_int64_t fraction = value - integer; + rt_int64_t bit = 0; + rt_uint32_t frac20 = 0; + rt_bool_t negative = fraction > scale / 2; + int frac_hi; + + fraction = negative ? scale - fraction : fraction; + *integer_part = (int)(integer / scale) + (negative ? 1 : 0); + + for (int i = 0; i < 20; ++i) + { + if (bit >= scale) + { + frac20 |= 1U << (19 - i); + fraction -= scale; + } + fraction *= 2; + bit = fraction; + } + + if (negative) + { + frac20 = (~frac20 + 1U) & 0xfffffU; + frac_hi = 0x10 | ((frac20 >> 16) & 0xf) | RT_BIT(5); + } + else + { + frac_hi = ((frac20 >> 16) & 0xf) | RT_BIT(5); + } + + *frac_reg = (0x20U << 24) | ((rt_uint32_t)frac_hi << 16) | + (frac20 & 0xffffU); +} + +static void spacemit_hdmi_pll_program(struct spacemit_hdmi *hdmi, + rt_uint32_t pixel_clock_khz) +{ + int integer_part; + rt_uint32_t frac_reg; + rt_uint32_t div_reg, post_reg; + int pll8 = spacemit_hdmi_pll8(pixel_clock_khz); + int pll6 = spacemit_hdmi_pll6(pixel_clock_khz); + int pll5 = spacemit_hdmi_pll5(pixel_clock_khz); + + spacemit_hdmi_pll_fraction(pixel_clock_khz, &integer_part, &frac_reg); + + div_reg = (0x50U << 24) | + ((0x0dU | ((rt_uint32_t)pll6 << 4) | (2U << 6)) << 16) | + ((0x40U | (rt_uint32_t)pll5) << 8) | + ((rt_uint32_t)integer_part & 0xffU); + post_reg = (8U << 8) | ((rt_uint32_t)pll8 << 5) | 1U; + + spacemit_hdmi_writel(hdmi, SPACEMIT_HDMI_PLL_FRAC, frac_reg); + spacemit_hdmi_writel(hdmi, SPACEMIT_HDMI_PLL_DIV, div_reg); + spacemit_hdmi_writel(hdmi, SPACEMIT_HDMI_PLL_POST, post_reg); +} + +static rt_err_t spacemit_hdmi_detect( + struct spacemit_display_connector *connector, rt_bool_t *connected) +{ + struct spacemit_hdmi *hdmi; + + if (!connector || !connected) + { + return -RT_EINVAL; + } + + hdmi = connector->priv; + *connected = !!(spacemit_hdmi_readl(hdmi, + SPACEMIT_HDMI_PHY_STATUS) & SPACEMIT_HDMI_PHY_HPD); + + return RT_EOK; +} + +static rt_err_t spacemit_hdmi_get_timing( + struct spacemit_display_connector *connector, + struct spacemit_display_timing *timing) +{ + if (!connector || !timing) + { + return -RT_EINVAL; + } + + *timing = spacemit_hdmi_1080p60; + return RT_EOK; +} + +static rt_err_t spacemit_hdmi_prepare(struct spacemit_hdmi *hdmi) +{ + rt_err_t err; + + if (hdmi->prepared) + { + return RT_EOK; + } + + if ((err = rt_clk_prepare_enable(hdmi->mclk))) + { + return err; + } + if ((err = rt_clk_set_rate(hdmi->mclk, SPACEMIT_HDMI_MCLK_RATE))) + { + rt_clk_disable_unprepare(hdmi->mclk); + return err; + } + if ((err = rt_reset_control_deassert(hdmi->rstc))) + { + rt_clk_disable_unprepare(hdmi->mclk); + return err; + } + + rt_hw_us_delay(10); + hdmi->prepared = RT_TRUE; + return RT_EOK; +} + +static rt_err_t spacemit_hdmi_enable( + struct spacemit_display_connector *connector, + const struct spacemit_display_timing *timing) +{ + rt_err_t err; + rt_bool_t connected; + rt_uint32_t pixel_clock_khz; + struct spacemit_hdmi *hdmi; + + if (!connector || !timing || !timing->pixelclock) + { + return -RT_EINVAL; + } + + hdmi = connector->priv; + if (hdmi->enabled) + { + return RT_EOK; + } + if ((err = spacemit_hdmi_prepare(hdmi))) + { + return err; + } + + pixel_clock_khz = (rt_uint32_t)(timing->pixelclock / 1000ULL); + + spacemit_hdmi_writel(hdmi, SPACEMIT_HDMI_PHY_ANALOG, 0xae5c410fU); + spacemit_hdmi_update_bits(hdmi, SPACEMIT_HDMI_PHY_ANALOG, + 0x3U << 29, 0x1U << 29); + spacemit_hdmi_update_bits(hdmi, SPACEMIT_HDMI_PHY_ANALOG, + 0xfU << 18, 0x7U << 18); + spacemit_hdmi_update_bits(hdmi, SPACEMIT_HDMI_PHY_ANALOG, + 0x3U << 14, 0); + + spacemit_hdmi_writel(hdmi, SPACEMIT_HDMI_COLOR_DEPTH, + 0x0000000dU | (4U << 4)); + spacemit_hdmi_pll_program(hdmi, pixel_clock_khz); + spacemit_hdmi_writel(hdmi, SPACEMIT_HDMI_PLL_CTRL, 0); + spacemit_hdmi_writel(hdmi, SPACEMIT_HDMI_PLL_CTRL, 3); + rt_hw_us_delay(100); + spacemit_hdmi_writel(hdmi, SPACEMIT_HDMI_PHY_CTRL, + 0x1c208000U | SPACEMIT_HDMI_EIGHT_BPP); + rt_hw_dsb(); + + hdmi->enabled = RT_TRUE; + spacemit_hdmi_detect(connector, &connected); + LOG_D("%ux%u@%u, pclk=%u kHz, mclk=%lu Hz, HPD=%d, pll=0x%08x", + timing->hactive, timing->vactive, timing->refresh, + pixel_clock_khz, rt_clk_get_rate(hdmi->mclk), connected, + spacemit_hdmi_readl(hdmi, SPACEMIT_HDMI_PLL_CTRL)); + + return RT_EOK; +} + +static rt_err_t spacemit_hdmi_disable( + struct spacemit_display_connector *connector) +{ + struct spacemit_hdmi *hdmi; + + if (!connector) + { + return -RT_EINVAL; + } + + hdmi = connector->priv; + if (hdmi->enabled) + { + spacemit_hdmi_writel(hdmi, SPACEMIT_HDMI_PLL_CTRL, 0); + rt_hw_us_delay(100); + hdmi->enabled = RT_FALSE; + } + + if (hdmi->prepared) + { + rt_clk_disable_unprepare(hdmi->mclk); + hdmi->prepared = RT_FALSE; + } + + return RT_EOK; +} + +static const struct spacemit_display_connector_ops spacemit_hdmi_ops = +{ + .detect = spacemit_hdmi_detect, + .get_timing = spacemit_hdmi_get_timing, + .enable = spacemit_hdmi_enable, + .disable = spacemit_hdmi_disable, +}; + +static rt_err_t spacemit_hdmi_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct spacemit_hdmi *hdmi = rt_calloc(1, sizeof(*hdmi)); + + if (!hdmi) + { + return -RT_ENOMEM; + } + + hdmi->dev = dev; + hdmi->regs = rt_dm_dev_iomap(dev, 0); + if (!hdmi->regs) + { + err = -RT_EIO; + goto _fail; + } + + hdmi->mclk = rt_clk_get_by_name(dev, "hmclk"); + if (rt_is_err(hdmi->mclk)) + { + err = rt_ptr_err(hdmi->mclk); + hdmi->mclk = RT_NULL; + goto _fail_unmap; + } + + hdmi->rstc = rt_reset_control_get_by_name(dev, "hdmi_reset"); + if (rt_is_err(hdmi->rstc)) + { + err = rt_ptr_err(hdmi->rstc); + hdmi->rstc = RT_NULL; + goto _fail_clk; + } + + if ((err = spacemit_display_connector_register(&hdmi->connector, + dev->ofw_node, &spacemit_hdmi_ops, hdmi))) + { + goto _fail_reset; + } + + pdev->parent.user_data = hdmi; + LOG_D("connector ready: %s", rt_ofw_node_full_name(dev->ofw_node)); + + return RT_EOK; + +_fail_reset: + rt_reset_control_put(hdmi->rstc); +_fail_clk: + rt_clk_put(hdmi->mclk); +_fail_unmap: + rt_iounmap(hdmi->regs); +_fail: + rt_free(hdmi); + return err; +} + +static rt_err_t spacemit_hdmi_remove(struct rt_platform_device *pdev) +{ + struct spacemit_hdmi *hdmi = pdev->parent.user_data; + + if (!hdmi) + { + return RT_EOK; + } + + spacemit_hdmi_disable(&hdmi->connector); + spacemit_display_connector_unregister(&hdmi->connector); + rt_reset_control_assert(hdmi->rstc); + rt_reset_control_put(hdmi->rstc); + rt_clk_put(hdmi->mclk); + rt_iounmap(hdmi->regs); + rt_free(hdmi); + pdev->parent.user_data = RT_NULL; + + return RT_EOK; +} + +static const struct rt_ofw_node_id spacemit_hdmi_ids[] = +{ + { .compatible = "spacemit,hdmi" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_hdmi_driver = +{ + .name = "hdmi-spacemit", + .ids = spacemit_hdmi_ids, + .probe = spacemit_hdmi_probe, + .remove = spacemit_hdmi_remove, +}; + +rt_err_t spacemit_hdmi_driver_register(void) +{ + return rt_platform_driver_register(&spacemit_hdmi_driver); +} diff --git a/bsp/spacemit/dm/graphic/logo/Kconfig b/bsp/spacemit/dm/graphic/logo/Kconfig new file mode 100644 index 000000000000..060eeee53b8d --- /dev/null +++ b/bsp/spacemit/dm/graphic/logo/Kconfig @@ -0,0 +1,5 @@ +config RT_GRAPHIC_LOGO_BIANBU_CLUT224 + bool "Standard 224-color Bianbu logo" + +config RT_GRAPHIC_LOGO_SPACEMIT_CLUT224 + bool "Standard 224-color Spacemit logo" diff --git a/bsp/spacemit/dm/graphic/logo/Kconfig.path b/bsp/spacemit/dm/graphic/logo/Kconfig.path new file mode 100644 index 000000000000..83a3f0012e90 --- /dev/null +++ b/bsp/spacemit/dm/graphic/logo/Kconfig.path @@ -0,0 +1,10 @@ +if RT_GRAPHIC_LOGO_BIANBU_CLUT224 + config RT_GRAPHIC_LOGO_BIANBU_CLUT224_PATH + string + default "../dm/graphic/logo/logo-bianbu-clut224.ppm" +endif +if RT_GRAPHIC_LOGO_SPACEMIT_CLUT224 + config RT_GRAPHIC_LOGO_SPACEMIT_CLUT224_PATH + string + default "../dm/graphic/logo/logo-spacemit-clut224.ppm" +endif diff --git a/bsp/spacemit/dm/graphic/logo/logo-bianbu-clut224.ppm b/bsp/spacemit/dm/graphic/logo/logo-bianbu-clut224.ppm new file mode 100644 index 000000000000..8f9aeeaf8e7c --- /dev/null +++ b/bsp/spacemit/dm/graphic/logo/logo-bianbu-clut224.ppm @@ -0,0 +1,9333 @@ +P3 +256 256 +255 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +6 7 2 28 33 10 49 59 17 67 79 24 80 96 28 95 113 33 108 128 38 121 144 43 +135 160 47 148 175 52 153 181 54 153 182 54 164 195 58 164 195 58 168 200 59 176 209 62 +176 209 62 168 200 59 164 195 58 164 195 58 153 182 54 153 181 54 148 175 52 135 160 47 +121 144 43 108 128 38 95 113 33 80 96 28 67 79 24 49 59 17 26 31 9 6 7 2 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 2 2 1 26 31 9 59 70 21 90 107 32 114 135 40 136 161 48 159 189 56 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 175 208 62 +159 189 56 136 161 48 112 134 40 89 106 31 58 69 20 26 31 9 2 2 1 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 3 3 1 37 43 13 76 90 27 108 128 38 +139 166 49 169 201 60 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 169 201 60 139 166 49 +108 128 38 75 89 26 37 43 13 3 3 1 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +8 10 3 41 49 15 82 98 29 124 147 44 166 197 58 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 169 201 60 135 161 48 94 111 33 54 64 19 12 14 4 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 1 2 0 35 42 12 82 98 29 129 153 45 +173 205 61 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 175 207 62 +141 167 50 94 111 33 41 49 15 1 2 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 10 12 4 63 75 22 112 134 40 162 192 57 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 162 192 57 111 132 39 61 72 21 10 11 3 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 7 2 54 64 19 +111 132 39 168 200 59 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 171 203 60 124 147 44 +65 77 23 9 11 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 4 5 1 58 69 20 118 140 42 170 202 60 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 169 201 60 117 139 41 57 67 20 4 5 1 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 26 31 9 94 111 33 162 192 57 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 164 195 58 105 125 37 31 37 11 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 6 2 59 70 21 +129 153 45 175 208 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 141 167 50 +71 84 25 7 8 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 14 17 5 82 98 29 159 189 56 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 162 193 57 94 111 33 18 21 6 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 28 33 10 106 126 37 170 202 60 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 175 207 62 153 181 54 153 181 54 143 169 50 +143 169 50 153 181 54 153 181 54 157 187 55 164 195 58 164 195 58 175 208 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 170 202 60 105 125 37 26 31 9 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +39 46 14 122 145 43 175 207 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 173 206 61 +154 183 54 131 156 46 109 129 38 88 104 31 67 79 24 54 64 19 41 48 14 28 33 10 +99 99 99 255 255 255 255 255 255 255 255 255 93 93 93 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 14 17 5 +28 33 10 41 48 14 54 64 19 67 79 24 88 104 31 109 129 38 133 157 47 155 184 54 +174 207 61 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 175 207 62 122 145 43 38 45 13 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 35 41 12 124 147 44 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 174 207 61 149 178 53 117 139 41 86 102 30 55 65 19 23 27 8 3 3 1 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 27 27 27 +238 238 238 255 255 255 255 255 255 242 242 242 13 13 13 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +3 4 1 24 29 9 55 65 19 86 102 30 118 140 42 149 178 53 174 207 61 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +122 145 43 35 41 12 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 30 35 10 119 142 42 175 208 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 162 192 57 121 144 43 78 93 27 +39 46 14 7 8 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 183 183 183 +255 255 255 255 255 255 255 255 255 157 157 157 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 8 2 41 48 14 +80 96 28 121 144 43 162 192 57 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 175 208 62 119 142 42 30 35 10 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 19 23 7 112 134 40 175 207 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 162 193 57 114 135 40 66 78 23 26 31 9 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 99 99 99 255 255 255 +255 255 255 255 255 255 255 255 255 60 60 60 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 26 31 9 67 79 24 115 137 41 163 193 57 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 175 207 62 112 134 40 19 23 7 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +7 8 2 82 98 29 168 199 59 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 175 207 62 141 167 50 94 111 33 +47 55 16 3 3 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 21 21 21 234 234 234 255 255 255 +255 255 255 255 255 255 219 219 219 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 0 35 42 12 +82 98 29 129 153 45 173 206 61 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 169 201 60 94 111 33 8 10 3 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 54 64 19 +154 183 54 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 175 207 62 135 161 48 77 92 27 18 21 6 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 161 161 161 255 255 255 255 255 255 +255 255 255 255 255 255 124 124 124 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 14 16 5 65 77 23 129 153 45 175 207 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 157 187 55 +65 77 23 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 31 37 11 136 161 48 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +138 164 48 77 92 27 19 22 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 60 60 60 254 254 254 255 255 255 255 255 255 +255 255 255 252 252 252 27 27 27 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 19 23 7 78 93 27 139 166 49 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 135 160 47 30 35 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 3 4 1 82 98 29 171 203 60 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 166 197 58 105 125 37 32 38 11 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 6 6 6 215 215 215 255 255 255 255 255 255 255 255 255 +255 255 255 187 187 187 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +28 34 10 94 111 33 162 193 57 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 173 205 61 94 111 33 5 6 2 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 41 48 14 148 175 52 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 133 157 47 63 75 22 6 7 2 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 129 129 129 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 88 88 88 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 6 7 2 65 77 23 134 159 47 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 147 175 52 41 48 14 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +8 10 3 103 122 36 175 207 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +173 205 61 112 134 40 35 41 12 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 37 37 37 246 246 246 255 255 255 255 255 255 255 255 255 255 255 255 +241 241 241 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 71 71 71 190 190 190 215 215 215 234 234 234 238 238 238 +238 238 238 238 238 238 238 238 238 231 231 231 215 215 215 198 198 198 180 180 180 143 143 143 +110 110 110 74 74 74 34 34 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 35 41 12 114 135 40 173 206 61 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 175 207 62 101 120 35 8 10 3 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 37 43 13 +149 178 53 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 167 198 59 100 119 35 +21 25 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 180 180 180 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +154 154 154 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 27 27 27 149 149 149 249 249 249 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 234 234 234 180 180 180 124 124 124 53 53 53 2 2 2 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 20 6 +88 105 31 165 196 58 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 153 182 54 +41 48 14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 1 86 102 30 173 205 61 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 164 195 58 86 102 30 10 11 3 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 66 66 66 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +60 60 60 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 34 34 34 169 169 169 +254 254 254 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 234 234 234 +161 161 161 71 71 71 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 10 12 4 88 104 31 166 197 58 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +173 205 61 84 99 29 2 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 21 25 7 133 157 47 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 168 199 59 94 111 33 12 14 4 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +3 3 3 208 208 208 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 215 215 215 +1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +60 60 60 198 198 198 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 231 231 231 139 139 139 27 27 27 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 9 11 3 82 98 29 166 197 58 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 138 164 48 23 27 8 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 55 65 19 166 197 58 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +170 202 60 95 113 33 13 16 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +99 99 99 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 119 119 119 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 3 3 3 110 110 110 242 242 242 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 249 249 249 165 165 165 48 48 48 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 14 17 5 97 115 34 170 202 60 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 165 196 58 54 64 19 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 1 1 0 82 98 29 175 207 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 124 147 44 +23 27 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 13 13 13 +231 231 231 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 252 252 252 27 27 27 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 34 34 34 187 187 187 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 252 252 252 165 165 165 +27 27 27 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 19 23 7 +111 132 39 175 208 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 175 208 62 94 111 33 2 2 1 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +13 16 5 127 151 45 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 143 169 50 44 52 15 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 133 133 133 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 183 183 183 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 114 114 114 249 249 249 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +246 246 246 129 129 129 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 44 52 15 143 169 50 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 131 156 46 14 17 5 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 35 41 12 +154 183 54 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 164 195 58 68 81 24 1 2 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 27 27 27 246 246 246 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 88 88 88 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 53 53 53 222 222 222 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 208 208 208 48 48 48 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 2 2 1 71 84 25 164 195 58 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 153 182 54 +33 39 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 56 66 20 169 201 60 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 124 147 44 19 22 7 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 161 161 161 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 239 239 239 8 8 8 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 21 21 21 +190 190 190 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 252 252 250 119 119 119 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 16 19 6 111 132 39 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +170 202 60 59 70 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 92 27 175 207 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +159 189 56 57 67 20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 42 42 42 252 252 252 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 149 149 149 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +6 6 6 161 161 161 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 161 161 161 6 6 6 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 52 62 18 156 185 55 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 175 208 62 88 105 31 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 2 2 1 103 122 36 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 106 126 37 +10 11 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 172 172 172 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 53 53 53 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 1 1 1 143 143 143 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 190 190 190 13 13 13 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 12 4 +108 128 38 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 101 120 35 2 2 1 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 8 9 3 122 145 43 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 162 193 57 55 65 19 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 48 48 48 254 254 254 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 215 215 215 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 143 143 143 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 198 198 198 +13 13 13 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 56 66 20 163 193 57 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 127 151 45 9 11 3 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 11 13 4 136 161 48 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 129 153 45 19 22 7 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 172 172 172 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 124 124 124 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 1 1 1 161 161 161 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +190 190 190 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 16 19 6 125 149 44 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 139 166 49 13 16 5 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +14 17 5 143 169 50 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 172 204 61 77 92 27 1 1 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 42 42 42 252 252 252 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 37 37 37 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 190 190 190 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 157 157 157 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 1 2 0 80 96 28 173 205 61 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 143 169 50 14 17 5 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 20 6 +146 173 51 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 157 187 55 39 46 14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 176 176 176 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 198 198 198 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 24 24 231 231 231 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 93 93 93 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 41 48 14 159 189 56 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 148 175 52 +19 22 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 21 25 8 151 179 53 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +134 159 47 17 20 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 48 48 48 254 254 254 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 105 106 101 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 66 66 66 254 254 254 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 242 242 242 37 37 37 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 14 17 5 130 154 46 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +154 183 54 24 29 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 21 25 8 155 184 54 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 99 117 35 +3 3 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 176 176 176 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 252 252 250 21 21 21 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 157 157 157 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 187 187 187 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 4 1 +100 119 35 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 155 184 54 21 25 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 18 21 6 152 180 53 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 172 204 61 65 77 23 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 48 48 48 254 254 254 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 180 180 180 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 17 17 +238 238 238 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 84 84 84 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 67 79 24 173 205 61 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 152 180 53 18 21 6 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 14 17 5 147 175 52 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 164 195 58 44 52 15 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 172 172 172 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 88 88 88 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +124 124 124 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 215 215 215 2 2 2 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 47 55 16 165 196 58 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 149 178 53 16 19 6 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 10 12 4 141 167 50 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 154 183 54 28 34 10 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +34 34 34 252 252 252 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 242 242 242 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +13 13 13 241 241 241 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 77 77 77 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 30 35 10 155 184 54 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 144 171 51 12 14 4 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 8 10 3 138 164 48 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 139 166 49 17 20 6 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +143 143 143 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 165 165 165 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 154 154 154 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 183 183 183 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 17 20 6 141 168 50 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 136 161 48 8 9 3 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +2 2 1 121 144 43 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 134 159 47 10 11 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 13 13 13 +241 241 241 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 77 77 77 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 60 60 60 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 249 249 249 17 17 17 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 10 3 130 154 46 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 124 147 44 2 2 1 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +101 120 35 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +131 156 46 8 10 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 114 114 114 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +241 241 241 8 8 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 3 3 3 236 236 236 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 93 93 93 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 8 2 127 151 45 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 105 125 37 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 78 93 27 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 124 147 44 +6 7 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 222 222 222 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +161 161 161 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 176 176 176 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 154 154 154 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 5 1 +119 142 42 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +77 92 27 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 57 67 20 175 207 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 117 139 41 3 4 1 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 88 88 88 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +77 77 77 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 133 133 133 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 208 208 208 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +3 4 1 117 139 41 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +174 207 61 55 65 19 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 35 41 12 170 202 60 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 121 144 43 3 4 1 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 198 198 198 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 241 241 241 +8 8 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 93 93 93 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 239 239 239 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 3 4 1 122 145 43 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 169 201 60 32 38 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 12 14 4 153 181 54 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 129 153 45 6 7 2 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 60 60 60 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 161 161 161 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 80 80 80 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 8 8 8 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 4 5 1 125 149 44 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 155 184 54 13 16 5 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 1 2 0 125 149 44 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 136 161 48 8 10 3 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 172 172 172 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 77 77 77 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 74 74 74 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 24 24 24 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 7 8 2 133 157 47 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 127 151 45 2 2 1 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 92 110 32 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 139 166 49 9 11 3 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 27 27 27 252 252 250 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 239 239 239 6 6 6 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 88 88 88 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 13 13 13 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 10 12 4 141 168 50 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 89 106 31 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 54 64 19 175 208 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 154 183 54 17 20 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 129 129 129 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 161 161 161 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 110 110 110 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 6 6 6 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 20 6 155 184 54 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 175 208 62 56 66 20 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 21 25 8 166 197 58 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +165 196 58 28 34 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 3 3 3 222 222 222 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 77 77 77 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 154 154 154 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 231 231 231 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 30 35 10 166 197 58 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 164 195 58 19 23 7 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 2 0 131 156 46 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 173 205 61 +47 55 16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 77 77 77 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 246 246 246 10 10 10 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 208 208 208 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 187 187 187 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 44 52 15 +172 204 61 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 134 159 47 2 2 1 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +86 102 30 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 66 78 23 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 180 180 180 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 176 176 176 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 24 24 24 254 254 254 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 133 133 133 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +68 81 24 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 82 98 29 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 35 42 12 +173 205 61 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 99 117 35 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 27 27 27 252 252 252 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 99 99 99 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 110 110 110 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 60 60 60 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 101 120 35 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 173 205 61 +37 43 13 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 9 3 149 178 53 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 136 161 48 4 5 1 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 124 124 124 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 252 252 252 21 21 21 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 208 208 208 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 234 234 234 4 4 4 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 3 4 1 133 157 47 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +151 179 53 8 10 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 103 122 36 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 157 187 55 16 19 6 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 215 215 215 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 194 194 194 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +71 71 71 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 133 133 133 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 17 20 6 159 189 56 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 100 119 35 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 39 46 14 175 207 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 173 205 61 41 49 15 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 53 53 53 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 114 114 114 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 +198 198 198 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 252 252 250 27 27 27 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 39 46 14 172 204 61 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 175 207 62 41 48 14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 5 6 2 148 175 52 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 78 93 27 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 149 149 149 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 37 37 37 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 99 99 99 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 149 149 149 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 80 96 28 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 146 173 51 4 5 1 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 90 107 32 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 127 151 45 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +6 6 6 234 234 234 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 215 215 215 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 27 27 27 239 239 239 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 239 239 239 21 21 21 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 1 2 0 130 154 46 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 87 103 31 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 31 37 11 172 204 61 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 164 195 58 19 23 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +80 80 80 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 133 133 133 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 190 190 190 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 105 106 101 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 19 22 7 163 193 57 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 172 204 61 30 35 10 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 1 1 0 136 161 48 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 55 65 19 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +165 165 165 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 60 60 60 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 143 143 143 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 169 169 169 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 57 67 20 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 133 157 47 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 63 75 22 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +108 128 38 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 10 10 +242 242 242 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 239 239 239 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 119 119 119 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 215 215 215 13 13 13 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 109 129 38 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 59 70 21 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 6 7 2 155 184 54 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 159 189 56 +11 13 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 84 84 84 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 172 172 172 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 110 110 110 254 254 254 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +231 231 231 34 34 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 12 4 +157 187 55 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 156 185 55 7 8 2 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 89 106 31 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 55 65 19 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 169 169 169 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 99 99 99 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 124 124 124 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 236 236 236 +42 42 42 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +52 62 18 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 86 102 30 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +19 23 7 168 200 59 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 117 139 41 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 10 10 242 242 242 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 27 27 27 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +6 6 6 154 154 154 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 222 222 222 42 42 42 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 119 142 42 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 169 201 60 21 25 7 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +112 134 40 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 164 195 58 16 19 6 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 84 84 84 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 215 215 215 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 27 27 27 +198 198 198 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 208 208 208 27 27 27 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 17 20 6 165 196 58 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 111 132 39 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 30 35 10 +175 207 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 71 84 25 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 165 165 165 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 143 143 143 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 84 84 84 236 236 236 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 161 161 161 13 13 13 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 71 84 25 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 174 207 61 +28 34 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 119 142 42 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 143 169 50 2 2 1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 236 236 236 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 71 71 71 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 24 24 24 165 165 165 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 242 242 242 93 93 93 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 2 2 1 144 171 51 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +115 137 41 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 35 41 12 175 208 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 44 52 15 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 60 60 60 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +246 246 246 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 4 4 4 110 110 110 239 239 239 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 180 180 180 34 34 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 44 52 15 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +175 208 62 32 38 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 124 147 44 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 117 139 41 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 139 139 139 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +183 183 183 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 1 1 84 84 84 215 215 215 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 222 222 222 +80 80 80 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 119 142 42 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 121 144 43 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 37 43 13 175 208 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 170 202 60 21 25 8 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 215 215 215 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +114 114 114 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 84 84 84 +208 208 208 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 234 234 234 114 114 114 8 8 8 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 23 27 8 170 202 60 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 37 43 13 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 122 145 43 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 95 113 33 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 37 37 37 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +48 48 48 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 13 13 13 110 110 110 219 219 219 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 234 234 234 124 124 124 13 13 13 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 97 115 34 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 120 143 42 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 26 31 9 175 207 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 168 199 59 14 17 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 110 110 110 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 238 238 238 +2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 1 1 1 60 60 60 157 157 157 242 242 242 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 208 208 208 93 93 93 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 14 16 5 167 198 59 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 175 207 62 28 33 10 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 106 126 37 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 90 107 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 180 180 180 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 180 180 180 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 48 48 48 +133 133 133 222 222 222 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 239 239 239 157 157 157 +60 60 60 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 94 111 33 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 103 122 36 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 14 17 5 170 202 60 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +166 197 58 12 14 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 4 4 4 241 241 241 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 114 114 114 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 13 13 13 74 74 74 149 149 149 222 222 222 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 252 252 252 176 176 176 80 80 80 6 6 6 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 13 4 165 196 58 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 170 202 60 16 19 6 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 90 107 32 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +86 102 30 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 60 60 60 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 53 53 53 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 27 27 27 169 169 169 249 249 249 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 242 242 242 194 194 194 139 139 139 88 88 88 +34 34 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 89 106 31 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 88 104 31 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 6 7 2 162 193 57 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 166 198 59 +10 11 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 129 129 129 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 242 242 242 4 4 4 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 2 2 2 60 60 60 149 149 149 231 231 231 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 231 231 231 154 154 154 71 71 71 6 6 6 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 14 4 +167 198 59 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 162 192 57 6 7 2 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 63 75 22 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 97 115 34 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 198 198 198 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 183 183 183 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 71 71 71 176 176 176 +252 252 250 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 241 241 241 169 169 169 84 84 84 6 6 6 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +99 117 35 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 61 72 21 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 133 157 47 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 173 205 61 21 25 7 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 13 13 13 252 252 250 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 124 124 124 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +24 24 24 119 119 119 222 222 222 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 234 234 234 +133 133 133 27 27 27 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +19 23 7 173 205 61 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 131 156 46 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 26 31 9 175 208 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 112 134 40 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 74 74 74 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 60 60 60 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 4 4 4 93 93 93 215 215 215 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 249 249 249 165 165 165 53 53 53 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 114 135 40 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 175 208 62 25 30 9 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 97 115 34 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 35 41 12 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 133 133 133 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 246 246 246 6 6 6 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 77 77 77 208 208 208 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 180 180 180 34 34 34 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 35 42 12 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 94 111 33 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +4 5 1 162 192 57 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 134 159 47 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 190 190 190 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 190 190 190 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 84 84 84 +222 222 222 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 249 249 249 139 139 139 17 17 17 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 135 160 47 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 160 190 56 3 4 1 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +58 69 20 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 65 77 23 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 6 6 6 246 246 246 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 133 133 133 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +8 8 8 119 119 119 242 242 242 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 236 236 236 +84 84 84 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 65 77 23 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 55 65 19 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +119 142 42 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 165 196 58 7 8 2 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 60 60 60 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 80 80 80 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 24 24 24 161 161 161 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 161 161 161 13 13 13 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 6 7 2 164 195 58 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 115 137 41 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 10 3 +170 202 60 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 100 119 35 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 114 114 114 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 27 27 27 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 71 71 71 231 231 231 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 222 222 222 60 60 60 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 103 122 36 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 169 201 60 +8 9 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 63 75 22 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 32 38 11 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 172 172 172 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 234 234 234 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 17 17 165 165 165 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 249 249 249 88 88 88 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 32 38 11 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +59 70 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 121 144 43 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 139 166 49 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 222 222 222 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 180 180 180 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 84 84 84 +242 242 242 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 252 252 252 110 110 110 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 141 168 50 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +119 142 42 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 11 3 170 202 60 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 77 92 27 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +21 21 21 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 129 129 129 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +37 37 37 215 215 215 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 133 133 133 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 80 96 28 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +170 202 60 10 11 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 63 75 22 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 175 207 62 19 23 7 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +71 71 71 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 77 77 77 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 21 21 21 187 187 187 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 139 139 139 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 21 25 8 175 208 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 59 70 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 112 134 40 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 134 159 47 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +119 119 119 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 24 24 24 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 4 4 4 157 157 157 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +110 110 110 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 138 164 48 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 109 129 38 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 0 162 192 57 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 75 89 26 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +172 172 172 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 231 231 231 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 1 1 1 149 149 149 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +252 252 252 71 71 71 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 92 27 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 159 189 56 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 37 43 13 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 175 207 62 17 20 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +222 222 222 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 176 176 176 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 157 157 157 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 234 234 234 27 27 27 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 19 22 7 175 208 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 35 41 12 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 88 104 31 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 139 166 49 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 13 13 13 +254 254 254 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 124 124 124 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 165 165 165 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 183 183 183 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 141 168 50 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 84 99 29 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 138 164 48 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 88 105 31 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 53 53 53 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 77 77 77 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 8 8 208 208 208 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 99 99 99 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 90 107 32 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 134 159 47 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 11 13 4 174 207 61 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 39 46 14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 99 99 99 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 34 34 34 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 34 34 34 +234 234 234 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 234 234 234 13 13 13 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 41 48 14 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 173 206 61 9 11 3 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 51 61 18 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +164 195 58 2 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 139 139 139 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 246 246 246 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +74 74 74 254 254 254 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 129 129 129 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 1 164 195 58 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 49 59 17 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 90 107 32 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +114 135 40 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 180 180 180 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 208 208 208 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 154 154 154 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 239 239 239 13 13 13 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 117 139 41 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 88 105 31 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 131 156 46 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +67 79 24 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 222 222 222 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 169 169 169 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 17 17 17 236 236 236 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 110 110 110 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 68 81 24 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 129 153 45 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 3 4 1 169 201 60 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +25 30 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 10 10 252 252 252 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 129 129 129 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 119 119 119 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 208 208 208 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 28 34 10 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 168 199 59 3 3 1 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 37 43 13 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 162 193 57 +1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 48 48 48 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 88 88 88 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 10 10 10 238 238 238 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 42 42 42 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 +162 192 57 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 35 41 12 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 75 89 26 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 121 144 43 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 80 80 80 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 48 48 48 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 143 143 143 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 114 114 114 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +122 145 43 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 75 89 26 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 108 128 38 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 80 96 28 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 114 114 114 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 252 252 252 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 48 48 48 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 183 183 183 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +82 98 29 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 106 126 37 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 139 166 49 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 41 48 14 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 143 143 143 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 222 222 222 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 222 222 222 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 234 234 234 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +41 48 14 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 138 164 48 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 2 2 1 169 201 60 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 175 207 62 8 9 3 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 180 180 180 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 183 183 183 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 161 161 161 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 24 24 24 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +8 9 3 175 207 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 168 200 59 1 2 0 0 0 0 0 0 0 + +0 0 0 0 0 0 28 33 10 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 149 178 53 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 208 208 208 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 143 143 143 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 110 110 110 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 53 53 53 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 151 179 53 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 24 29 9 0 0 0 0 0 0 + +0 0 0 0 0 0 59 70 21 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 119 142 42 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 242 242 242 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 110 110 110 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 80 80 80 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 77 77 77 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 119 142 42 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 56 66 20 0 0 0 0 0 0 + +0 0 0 0 0 0 90 107 32 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 88 104 31 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 17 17 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 77 77 77 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 60 60 60 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 84 84 84 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 88 105 31 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 87 103 31 0 0 0 0 0 0 + +0 0 0 0 0 0 114 135 40 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 56 66 20 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 42 42 42 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 48 48 48 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 53 53 53 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 88 88 88 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 57 67 20 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 111 132 39 0 0 0 0 0 0 + +0 0 0 0 0 0 136 161 48 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 26 31 9 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 66 66 66 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 13 13 13 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 60 60 60 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 77 77 77 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 26 31 9 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 134 159 47 0 0 0 0 0 0 + +0 0 0 0 0 0 159 189 56 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 175 207 62 4 5 1 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 88 88 88 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +241 241 241 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 84 84 84 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 60 60 60 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 4 5 1 175 207 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 156 185 55 0 0 0 0 0 0 + +0 0 0 6 7 2 175 208 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 156 185 55 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 110 110 110 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +208 208 208 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 119 119 119 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 34 34 34 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 157 187 55 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 175 207 62 5 6 2 0 0 0 + +0 0 0 28 33 10 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 134 159 47 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 133 133 133 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +183 183 183 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 176 176 176 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 246 246 246 2 2 2 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 135 160 47 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 25 30 9 0 0 0 + +0 0 0 49 59 17 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 111 132 39 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 157 157 157 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +161 161 161 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 3 3 3 236 236 236 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 198 198 198 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 111 132 39 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 49 59 17 0 0 0 + +0 0 0 68 81 24 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 89 106 31 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 180 180 180 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +139 139 139 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 71 71 71 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 139 139 139 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 89 106 31 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 66 78 23 0 0 0 + +0 0 0 80 96 28 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 71 84 25 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 198 198 198 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +114 114 114 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 161 161 161 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 71 71 71 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 68 81 24 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 78 93 27 0 0 0 + +0 0 0 95 113 33 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 56 66 20 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 215 215 215 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +93 93 93 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 27 27 27 249 249 249 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 239 239 239 6 6 6 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 55 65 19 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 94 111 33 0 0 0 + +0 0 0 108 128 38 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 44 52 15 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 222 222 222 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +71 71 71 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 143 143 143 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 161 161 161 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 41 49 15 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 106 126 37 0 0 0 + +0 0 0 122 145 43 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 28 34 10 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 236 236 236 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +48 48 48 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 37 37 37 249 249 249 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 53 53 53 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 28 34 10 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 120 143 42 0 0 0 + +0 0 0 135 161 48 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 14 17 5 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 249 249 249 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +34 34 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 187 187 187 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 208 208 208 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 14 17 5 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 133 157 47 0 0 0 + +0 0 0 147 175 52 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 175 208 62 3 4 1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +17 17 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +105 106 101 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 84 84 84 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 3 3 1 175 208 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 146 173 51 0 0 0 + +0 0 0 153 181 54 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 170 202 60 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 17 17 17 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 254 254 254 +3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 42 42 42 +246 246 246 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 208 208 208 2 2 2 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 168 199 59 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 151 179 53 0 0 0 + +0 0 0 157 187 55 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 165 196 58 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 34 34 34 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 241 241 241 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 21 21 21 219 219 219 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 74 74 74 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 164 195 58 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 155 184 54 0 0 0 + +0 0 0 162 192 57 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 162 192 57 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 37 37 37 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 222 222 222 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 190 190 190 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 172 172 172 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 159 189 56 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 160 190 56 0 0 0 + +0 0 0 166 197 58 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 157 187 55 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 42 42 42 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 215 215 215 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 172 172 172 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 242 242 242 27 27 27 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 155 184 54 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 164 195 58 0 0 0 + +0 0 0 170 202 60 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 153 181 54 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 42 42 42 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 208 208 208 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 3 3 3 165 165 165 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 93 93 93 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 151 179 53 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 169 201 60 0 0 0 + +0 0 0 174 207 61 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 148 175 52 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 42 42 42 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 198 198 198 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 8 8 8 172 172 172 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +172 172 172 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 146 173 51 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 174 207 61 0 0 0 + +0 0 0 174 207 61 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 148 175 52 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 48 48 48 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 190 190 190 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 17 17 17 194 194 194 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 215 215 215 +17 17 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 144 171 51 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 174 207 61 0 0 0 + +0 0 0 170 202 60 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 153 182 54 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 48 48 48 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 183 183 183 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +37 37 37 215 215 215 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 241 241 241 42 42 42 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 148 175 52 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 169 201 60 0 0 0 + +0 0 0 166 197 58 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 157 187 55 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 53 53 53 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 176 176 176 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 84 84 84 +241 241 241 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 249 249 249 71 71 71 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 152 180 53 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 164 195 58 0 0 0 + +0 0 0 162 192 57 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 162 193 57 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 53 53 53 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 176 176 176 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 10 10 149 149 149 254 254 254 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 254 254 254 93 93 93 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 155 184 54 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 160 190 56 0 0 0 + +0 0 0 157 187 55 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 167 198 59 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 48 48 48 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 176 176 176 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 53 53 53 215 215 215 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 114 114 114 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 160 190 56 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 155 184 54 0 0 0 + +0 0 0 153 181 54 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 171 203 60 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 42 42 42 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 176 176 176 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 17 17 17 143 143 143 252 252 252 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 254 254 254 110 110 110 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 170 202 60 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 151 179 53 0 0 0 + +0 0 0 147 175 52 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 175 208 62 4 5 1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 34 34 34 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 180 180 180 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 1 1 93 93 93 234 234 234 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 252 252 252 93 93 93 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 3 3 1 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 146 173 51 0 0 0 + +0 0 0 135 160 47 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 17 20 6 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 24 24 24 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 180 180 180 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 53 53 53 +198 198 198 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +246 246 246 77 77 77 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 12 14 4 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 133 157 47 0 0 0 + +0 0 0 121 144 43 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 31 37 11 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 17 17 17 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 180 180 180 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 48 48 48 169 169 169 254 254 254 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 222 222 222 +53 53 53 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 24 29 9 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 120 143 42 0 0 0 + +0 0 0 108 128 38 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 44 52 15 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 8 8 8 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 190 190 190 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 48 48 48 169 169 169 254 254 254 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 190 190 190 21 21 21 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 44 52 15 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 105 125 37 0 0 0 + +0 0 0 94 111 33 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 59 70 21 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 252 252 252 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 198 198 198 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 66 66 66 183 183 183 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 252 252 252 129 129 129 2 2 2 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 63 75 22 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 92 110 32 0 0 0 + +0 0 0 80 96 28 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 75 89 26 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 246 246 246 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 208 208 208 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 13 13 13 105 106 101 +208 208 208 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 208 208 208 53 53 53 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 82 98 29 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 78 93 27 0 0 0 + +0 0 0 68 81 24 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 90 107 32 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 234 234 234 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 219 219 219 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 37 37 37 133 133 133 238 238 238 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 246 246 246 129 129 129 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 99 117 35 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 66 78 23 0 0 0 + +0 0 0 49 59 17 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 112 134 40 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 215 215 215 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 231 231 231 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 13 13 13 99 99 99 194 194 194 254 254 254 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 254 254 254 +169 169 169 34 34 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 119 142 42 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 47 55 16 0 0 0 + +0 0 0 26 31 9 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 136 161 48 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 194 194 194 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 242 242 242 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 66 66 66 +161 161 161 242 242 242 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 187 187 187 53 53 53 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 138 164 48 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 25 30 9 0 0 0 + +0 0 0 6 7 2 175 208 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 159 189 56 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 176 176 176 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 2 2 2 60 60 60 149 149 149 231 231 231 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 252 252 252 176 176 176 60 60 60 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 157 187 55 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 175 207 62 5 6 2 0 0 0 + +0 0 0 0 0 0 159 189 56 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 175 208 62 7 8 2 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 157 157 157 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +24 24 24 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 42 42 42 129 129 129 222 222 222 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 239 239 239 143 143 143 34 34 34 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 4 5 1 173 206 61 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 156 185 55 0 0 0 0 0 0 + +0 0 0 0 0 0 136 161 48 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 28 34 10 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 133 133 133 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +42 42 42 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 60 60 60 143 143 143 +222 222 222 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 246 246 246 169 169 169 +84 84 84 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 32 38 11 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 133 157 47 0 0 0 0 0 0 + +0 0 0 0 0 0 114 135 40 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 57 67 20 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 119 119 119 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +60 60 60 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 4 4 4 66 66 66 149 149 149 231 231 231 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 234 234 234 165 165 165 84 84 84 10 10 10 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 63 75 22 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 111 132 39 0 0 0 0 0 0 + +0 0 0 0 0 0 89 106 31 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 89 106 31 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 99 99 99 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +80 80 80 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 +77 77 77 161 161 161 236 236 236 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 234 234 234 +176 176 176 110 110 110 42 42 42 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 95 113 33 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 86 102 30 0 0 0 0 0 0 + +0 0 0 0 0 0 58 69 20 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 121 144 43 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 77 77 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +105 106 101 0 0 0 0 0 0 0 0 0 0 0 0 60 60 60 161 161 161 241 241 241 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 242 242 242 208 208 208 172 172 172 124 124 124 77 77 77 27 27 27 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 127 151 45 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 55 65 19 0 0 0 0 0 0 + +0 0 0 0 0 0 26 31 9 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 154 183 54 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 48 48 48 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +133 133 133 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 17 17 +37 37 37 60 60 60 77 77 77 93 93 93 114 114 114 133 133 133 154 154 154 165 165 165 +172 172 172 187 187 187 190 190 190 208 208 208 215 215 215 222 222 222 234 234 234 238 238 238 +254 254 254 239 239 239 238 238 238 238 238 238 238 238 238 238 238 238 222 222 222 215 215 215 +208 208 208 190 190 190 176 176 176 154 154 154 129 129 129 110 110 110 88 88 88 60 60 60 +24 24 24 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 159 189 56 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 23 27 8 0 0 0 0 0 0 + +0 0 0 0 0 0 1 2 0 168 200 59 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 175 208 62 12 14 4 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 17 17 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +165 165 165 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +14 17 5 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 168 199 59 1 1 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 139 166 49 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 44 52 15 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 241 241 241 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +194 194 194 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +47 55 16 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 138 164 48 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 108 128 38 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 82 98 29 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 208 208 208 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +222 222 222 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +80 96 28 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 106 126 37 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 75 89 26 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 124 147 44 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 180 180 180 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +252 252 250 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +124 147 44 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 75 89 26 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 37 43 13 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 164 195 58 +1 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 149 149 149 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 34 34 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 1 +165 196 58 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 35 41 12 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 3 3 1 168 200 59 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +31 37 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 13 16 5 135 161 48 100 119 35 66 78 23 +31 37 11 3 4 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 119 119 119 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 77 77 77 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 37 43 13 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 167 198 59 2 2 1 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 130 154 46 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +71 84 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 151 179 53 176 209 62 176 209 62 +176 209 62 173 205 61 147 175 52 117 139 41 88 105 31 59 70 21 30 35 10 1 2 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 88 88 88 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 119 119 119 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 82 98 29 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 127 151 45 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 90 107 32 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +115 137 41 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 108 128 38 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 166 197 58 +135 161 48 105 125 37 75 89 26 44 52 15 14 17 5 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 48 48 48 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 157 157 157 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 125 149 44 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 88 104 31 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 49 59 17 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +164 195 58 3 3 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 65 77 23 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 165 196 58 141 167 50 117 139 41 +88 105 31 59 70 21 35 42 12 6 7 2 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 10 10 252 252 252 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 198 198 198 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 1 167 198 59 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 47 55 16 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 10 12 4 174 207 61 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 41 49 15 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 21 25 8 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 173 206 61 152 180 53 127 151 45 103 122 36 78 93 27 +56 66 20 32 38 11 8 9 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 219 219 219 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 239 239 239 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 39 46 14 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 173 206 61 8 10 3 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 136 161 48 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 92 110 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 151 179 53 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 159 189 56 135 161 48 111 132 39 90 107 32 68 81 24 +49 59 17 28 33 10 6 7 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 180 180 180 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 37 37 37 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 88 105 31 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 134 159 47 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 86 102 30 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 144 171 51 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 99 117 35 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 160 190 56 139 166 49 119 142 42 99 117 35 77 92 27 +56 66 20 39 46 14 19 23 7 4 5 1 0 0 0 0 0 0 0 0 0 133 133 133 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 88 88 88 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 14 17 5 37 43 13 59 70 21 80 96 28 +103 122 36 124 147 44 146 173 51 95 113 33 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 146 173 51 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 84 99 29 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 37 43 13 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 19 23 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 49 59 17 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 160 190 56 144 171 51 124 147 44 144 171 51 +201 207 125 216 221 200 216 221 200 231 235 222 245 247 240 252 252 250 255 255 255 255 255 255 +255 255 255 255 255 255 143 143 143 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 2 2 1 18 21 6 38 45 13 55 65 19 75 89 26 92 110 32 +111 132 39 130 154 46 148 175 52 170 202 60 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 54 64 19 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 28 34 10 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 35 41 12 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 0 162 192 57 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 75 89 26 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 6 2 167 198 59 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +201 207 125 201 207 125 201 207 125 97 115 34 80 96 28 66 78 23 52 62 18 39 46 14 +24 29 9 10 12 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 11 3 +21 25 8 37 43 13 51 61 18 66 78 23 82 98 29 99 117 35 112 134 40 127 151 45 +144 171 51 159 189 56 174 207 61 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 171 203 60 8 9 3 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 86 102 30 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 159 189 56 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 111 132 39 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 136 161 48 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 119 142 42 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 164 195 58 154 183 54 144 171 51 133 157 47 122 145 43 +112 134 40 103 122 36 92 110 32 82 98 29 71 84 25 59 70 21 49 59 17 39 46 14 +33 39 11 23 27 8 19 23 7 12 14 4 6 7 2 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 11 3 16 19 6 23 27 8 +35 41 12 41 48 14 47 55 16 59 70 21 66 78 23 71 84 25 82 98 29 90 107 32 +99 117 35 111 132 39 124 147 44 136 161 48 148 175 52 162 192 57 173 206 61 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 127 151 45 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 144 171 51 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 109 129 38 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 61 72 21 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 175 208 62 23 27 8 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 63 75 22 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 168 200 59 164 195 58 +155 184 54 153 181 54 141 167 50 139 166 49 129 153 45 125 149 44 117 139 41 117 139 41 +117 139 41 108 128 38 105 125 37 105 125 37 105 125 37 105 125 37 105 125 37 97 115 34 +94 111 33 94 111 33 94 111 33 94 111 33 94 111 33 86 102 30 82 98 29 86 102 30 +94 111 33 94 111 33 94 111 33 99 117 35 105 125 37 105 125 37 105 125 37 109 129 38 +117 139 41 117 139 41 117 139 41 120 143 42 129 153 45 129 153 45 129 153 45 136 161 48 +143 169 50 153 181 54 162 192 57 167 198 59 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 75 89 26 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 26 31 9 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 59 70 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 11 3 170 202 60 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 84 99 29 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 9 3 +168 200 59 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 175 207 62 18 21 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 86 102 30 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +169 201 60 8 10 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 121 144 43 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 146 173 51 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +117 139 41 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 131 156 46 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 144 171 51 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +118 140 42 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 61 72 21 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 32 38 11 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +56 66 20 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 71 84 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 37 43 13 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +59 70 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 10 3 +169 201 60 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 101 120 35 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +6 7 2 165 196 58 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +171 203 60 13 16 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 108 128 38 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 168 199 59 +7 8 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +117 139 41 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 166 197 58 8 9 3 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 101 120 35 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +112 134 40 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 10 12 4 168 200 59 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 114 135 40 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +57 67 20 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 68 81 24 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 31 37 11 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +44 52 15 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 75 89 26 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 55 65 19 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +4 5 1 162 192 57 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 141 167 50 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 136 161 48 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 170 202 60 +135 161 48 97 115 34 58 69 20 114 135 40 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 148 175 52 +1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 147 175 52 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 159 189 56 3 4 1 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 97 115 34 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 37 43 13 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 66 78 23 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +148 175 52 86 102 30 114 135 40 141 168 50 168 200 59 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 171 203 60 141 167 50 108 128 38 75 89 26 37 43 13 3 4 1 +0 0 0 0 0 0 7 8 2 164 195 58 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 71 84 25 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 44 52 15 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 94 111 33 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 26 31 9 175 208 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 112 134 40 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 6 7 2 162 192 57 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +170 202 60 11 13 4 0 0 0 0 0 0 0 0 0 19 23 7 41 49 15 63 75 22 +86 102 30 108 128 38 129 153 45 151 179 53 171 203 60 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 173 205 61 149 178 53 121 144 43 95 113 33 +66 78 23 32 38 11 3 4 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 68 81 24 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 159 189 56 6 7 2 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 114 135 40 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 175 208 62 25 30 9 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 133 157 47 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 173 206 61 23 27 8 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 87 103 31 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 71 84 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 18 21 6 41 48 14 63 75 22 +84 99 29 101 120 35 119 142 42 135 161 48 152 180 53 170 202 60 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 159 189 56 133 157 47 +105 125 37 78 93 27 52 62 18 25 30 9 3 3 1 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 141 167 50 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 84 99 29 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +21 25 8 173 205 61 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 131 156 46 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 63 75 22 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 103 122 36 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 14 16 5 169 201 60 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 135 161 48 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 11 3 28 33 10 +44 52 15 63 75 22 77 92 27 95 113 33 111 132 39 129 153 45 146 173 51 162 193 57 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 170 202 60 151 179 53 134 159 47 +112 134 40 97 115 34 77 92 27 58 69 20 37 43 13 10 12 4 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 44 52 15 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 163 193 57 10 11 3 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +104 124 37 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 61 72 21 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 6 7 2 162 193 57 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 169 201 60 +14 17 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 103 122 36 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 35 41 12 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +5 6 2 18 21 6 30 35 10 44 52 15 57 67 20 68 81 24 84 99 29 97 115 34 +109 129 38 122 145 43 134 159 47 144 171 51 154 183 54 164 195 58 175 208 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 164 195 58 152 180 53 139 166 49 127 151 45 115 137 41 103 122 36 +88 104 31 68 81 24 51 61 18 31 37 11 13 16 5 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 131 156 46 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 80 96 28 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 19 23 7 +171 203 60 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 162 192 57 6 7 2 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 89 106 31 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +90 107 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 24 29 9 173 205 61 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 108 128 38 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 11 3 +19 22 7 28 34 10 39 46 14 49 59 17 59 70 21 68 81 24 71 84 25 82 98 29 +84 99 29 94 111 33 99 117 35 105 125 37 112 134 40 117 139 41 125 149 44 129 153 45 +138 164 48 141 167 50 141 167 50 141 167 50 148 175 52 153 181 54 153 181 54 153 181 54 +157 187 55 164 195 58 164 195 58 164 195 58 164 195 58 164 195 58 164 195 58 164 195 58 +163 193 57 153 181 54 153 181 54 153 181 54 153 181 54 153 181 54 153 181 54 151 179 53 +141 167 50 136 161 48 129 153 45 122 145 43 117 139 41 109 129 38 105 125 37 97 115 34 +94 111 33 82 98 29 80 96 28 71 84 25 61 72 21 49 59 17 37 43 13 25 30 9 +13 16 5 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +47 55 16 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 157 187 55 6 7 2 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 101 120 35 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 87 103 31 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 14 17 5 170 202 60 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +164 195 58 12 14 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 108 128 38 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 170 202 60 14 17 5 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +135 161 48 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 65 77 23 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 20 6 170 202 60 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 169 201 60 14 16 5 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 105 125 37 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 94 111 33 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 21 25 8 172 204 61 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 94 111 33 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 55 65 19 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 135 161 48 1 1 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 99 117 35 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 103 122 36 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 26 31 9 175 207 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 169 201 60 17 20 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 103 122 36 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 167 198 59 13 16 5 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 7 2 153 182 54 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 173 206 61 35 41 12 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 14 17 5 169 201 60 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 175 207 62 25 30 9 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 122 145 43 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 103 122 36 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 19 22 7 168 200 59 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 92 110 32 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 89 106 31 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 90 107 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 101 120 35 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 119 142 42 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 38 45 13 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 173 205 61 25 30 9 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 88 104 31 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 169 201 60 19 23 7 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 30 9 170 202 60 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 139 166 49 3 4 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 30 35 10 173 206 61 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 175 208 62 35 42 12 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 122 145 43 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 117 139 41 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 8 2 +157 187 55 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 109 129 38 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 1 2 0 133 157 47 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +169 201 60 26 31 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 127 151 45 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 120 143 42 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 35 41 12 175 208 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 47 55 16 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +65 77 23 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 175 207 62 37 43 13 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 77 92 27 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +75 89 26 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 54 64 19 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +175 207 62 31 37 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 119 142 42 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 147 175 52 3 4 1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 1 0 135 161 48 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 144 171 51 3 4 1 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 26 31 9 170 202 60 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 164 195 58 +82 98 29 71 84 25 68 81 24 59 70 21 54 64 19 37 43 13 19 23 7 4 5 1 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 4 5 1 151 179 53 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +115 137 41 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 30 35 10 +175 207 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 78 93 27 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 30 35 10 172 204 61 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 86 102 30 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 1 2 0 19 23 7 44 52 15 66 78 23 +89 106 31 111 132 39 135 161 48 164 195 58 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +162 192 57 139 166 49 111 132 39 82 98 29 56 66 20 25 30 9 0 0 0 0 0 0 +0 0 0 0 0 0 80 96 28 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 174 207 61 +28 33 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +112 134 40 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 166 198 59 17 20 6 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 90 107 32 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 171 203 60 +28 34 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 1 28 34 10 +59 70 21 94 111 33 125 149 44 151 179 53 172 204 61 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 162 192 57 121 144 43 +78 93 27 49 59 17 166 198 59 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 109 129 38 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +19 23 7 169 201 60 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 117 139 41 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 6 7 2 151 179 53 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +136 161 48 1 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 10 12 4 44 52 15 75 89 26 108 128 38 139 166 49 170 202 60 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 168 199 59 18 21 6 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 88 104 31 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 57 67 20 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 41 48 14 174 207 61 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 76 90 27 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 26 31 9 66 78 23 106 126 37 +146 173 51 175 207 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 84 99 29 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 6 7 2 155 184 54 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 162 193 57 +14 17 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 92 110 32 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 171 203 60 37 43 13 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +7 8 2 41 49 15 77 92 27 117 139 41 162 192 57 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 153 182 54 6 7 2 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 61 72 21 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +115 137 41 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 3 4 1 139 166 49 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 155 184 54 14 16 5 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 3 3 1 35 42 12 82 98 29 129 153 45 +172 204 61 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 57 67 20 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 1 1 0 135 161 48 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 57 67 20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 30 35 10 169 201 60 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 125 149 44 1 2 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +3 3 1 41 48 14 86 102 30 131 156 46 170 202 60 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 170 202 60 146 173 51 127 151 45 112 134 40 +99 117 35 86 102 30 68 81 24 54 64 19 39 46 14 25 30 9 71 84 25 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 131 156 46 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 30 35 10 172 204 61 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 162 193 57 19 22 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 66 78 23 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 87 103 31 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 30 35 10 78 93 27 125 149 44 +168 199 59 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 160 190 56 136 161 48 112 134 40 +89 106 31 65 77 23 41 49 15 17 20 6 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 29 9 166 198 59 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 171 203 60 28 33 10 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 89 106 31 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 133 157 47 2 2 1 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 109 129 38 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 175 207 62 49 59 17 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 12 14 4 59 70 21 108 128 38 157 187 55 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 167 198 59 +136 161 48 104 124 37 71 84 25 39 46 14 9 11 3 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 4 5 1 139 166 49 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 86 102 30 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 5 6 2 147 175 52 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 88 105 31 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 8 2 +144 171 51 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 166 197 58 32 38 11 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 1 38 45 13 87 103 31 +136 161 48 174 207 61 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 154 183 54 121 144 43 89 106 31 57 67 20 24 29 9 1 1 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 97 115 34 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 146 173 51 4 5 1 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 41 48 14 175 207 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 174 207 61 44 52 15 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +23 27 8 162 193 57 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 159 189 56 21 25 8 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 13 16 5 63 75 22 115 137 41 163 193 57 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 170 202 60 135 161 48 97 115 34 +55 65 19 17 20 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 51 61 18 175 208 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 174 207 61 38 45 13 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 101 120 35 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 159 189 56 16 19 6 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 44 52 15 173 205 61 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 148 175 52 +13 16 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 32 38 11 +84 99 29 135 161 48 174 207 61 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 159 189 56 119 142 42 78 93 27 39 46 14 4 5 1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 19 23 7 162 192 57 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 99 117 35 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 10 3 151 179 53 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 135 161 48 4 5 1 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 71 84 25 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +136 161 48 7 8 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 6 7 2 51 61 18 104 124 37 155 184 54 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 152 180 53 106 126 37 63 75 22 +21 25 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 7 8 2 141 167 50 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +148 175 52 8 9 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 37 43 13 +173 205 61 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 108 128 38 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 92 110 32 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 124 147 44 4 5 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +19 22 7 71 84 25 124 147 44 170 202 60 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 159 189 56 112 134 40 67 79 24 21 25 8 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 1 0 117 139 41 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 172 204 61 +35 41 12 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +86 102 30 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 76 90 27 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 1 1 0 109 129 38 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 125 149 44 6 7 2 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 30 35 10 82 98 29 135 161 48 +175 208 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 167 198 59 129 153 45 82 98 29 +35 42 12 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +88 104 31 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 80 96 28 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +2 2 1 133 157 47 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 173 206 61 +47 55 16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 3 4 1 125 149 44 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 127 151 45 6 7 2 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 6 7 2 51 61 18 105 125 37 157 187 55 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 171 203 60 127 151 45 80 96 28 35 41 12 1 2 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 57 67 20 +175 208 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 130 154 46 1 2 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 21 25 7 165 196 58 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +164 195 58 30 35 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 8 2 131 156 46 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 130 154 46 8 9 3 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 20 6 68 81 24 +121 144 43 169 201 60 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 153 182 54 103 122 36 +54 64 19 8 9 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 35 41 12 168 200 59 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 164 195 58 19 22 7 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 54 64 19 175 208 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 157 187 55 21 25 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 10 3 135 161 48 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 134 159 47 9 11 3 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 33 39 11 86 102 30 139 166 49 175 207 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 171 203 60 127 151 45 78 93 27 28 33 10 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 29 9 159 189 56 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 175 207 62 51 61 18 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 90 107 32 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 148 175 52 13 16 5 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 11 3 +138 164 48 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 143 169 50 19 22 7 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 6 2 +49 59 17 103 122 36 155 184 54 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 153 182 54 +103 122 36 54 64 19 8 9 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 18 21 6 153 182 54 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 88 104 31 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 1 2 0 125 149 44 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 138 164 48 7 8 2 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +9 11 3 131 156 46 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 156 185 55 +31 37 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 19 23 7 68 81 24 119 142 42 168 199 59 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 173 205 61 130 154 46 78 93 27 28 33 10 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 13 16 5 146 173 51 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 124 147 44 1 2 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 12 14 4 153 182 54 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 125 149 44 6 7 2 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 6 7 2 125 149 44 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +166 197 58 47 55 16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +10 11 3 54 64 19 101 120 35 148 175 52 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +164 195 58 114 135 40 61 72 21 11 13 4 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 21 21 21 60 60 60 84 84 84 110 110 110 129 129 129 154 154 154 +180 180 180 198 198 198 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 236 236 236 +236 236 236 222 222 222 208 208 208 190 190 190 169 169 169 124 124 124 42 42 42 0 0 0 +0 0 0 0 0 0 8 10 3 139 166 49 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 152 180 53 12 14 4 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 33 39 11 169 201 60 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 125 149 44 6 7 2 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 4 5 1 111 132 39 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 173 205 61 67 79 24 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 9 11 3 44 52 15 88 105 31 136 161 48 +173 206 61 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 152 180 53 99 117 35 44 52 15 +3 3 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 24 24 24 71 71 71 110 110 110 154 154 154 +194 194 194 234 234 234 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 234 234 234 161 161 161 88 88 88 34 34 34 0 0 0 0 0 0 0 0 0 +0 0 0 6 7 2 130 154 46 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 168 200 59 32 38 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 52 62 18 174 207 61 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 127 151 45 6 7 2 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 77 92 27 175 207 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 105 125 37 4 5 1 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 1 +30 35 10 65 77 23 100 119 35 141 167 50 174 207 61 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 175 207 62 141 167 50 88 105 31 35 42 12 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 +60 60 60 110 110 110 169 169 169 222 222 222 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 215 215 215 129 129 129 +53 53 53 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +7 8 2 127 151 45 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +175 207 62 55 65 19 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 92 27 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 125 149 44 +5 6 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 61 72 21 170 202 60 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 135 160 47 17 20 6 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 21 25 8 49 59 17 77 92 27 104 124 37 135 161 48 170 202 60 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 168 200 59 119 142 42 +67 79 24 14 17 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 10 10 10 71 71 71 139 139 139 198 198 198 249 249 249 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 222 222 222 139 139 139 48 48 48 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 11 3 +135 160 47 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +75 89 26 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +101 120 35 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +141 168 50 103 122 36 82 98 29 63 75 22 41 48 14 19 23 7 2 2 1 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 39 46 14 162 192 57 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 159 189 56 41 48 14 0 0 0 +0 0 0 0 0 0 7 8 2 28 34 10 47 55 16 66 78 23 86 102 30 112 134 40 +141 167 50 168 199 59 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 160 190 56 105 125 37 51 61 18 6 7 2 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 +53 53 53 119 119 119 187 187 187 246 246 246 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +238 238 238 161 161 161 66 66 66 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 14 4 139 166 49 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 99 117 35 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +2 2 1 122 145 43 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 175 207 62 160 190 56 +146 173 51 130 154 46 112 134 40 99 117 35 86 102 30 76 90 27 66 78 23 57 67 20 +47 55 16 37 43 13 28 34 10 23 27 8 23 27 8 23 27 8 12 14 4 35 41 12 +154 183 54 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 173 205 61 127 151 45 +146 173 51 164 195 58 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +153 181 54 97 115 34 41 49 15 1 2 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 17 17 17 88 88 88 165 165 165 238 238 238 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 242 242 242 161 161 161 74 74 74 +4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 16 19 6 144 171 51 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 120 143 42 1 2 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 8 9 3 136 161 48 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 143 169 50 88 104 31 32 38 11 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 34 34 34 114 114 114 190 190 190 252 252 250 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 252 252 252 183 183 183 88 88 88 10 10 10 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 21 25 8 149 178 53 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 135 161 48 7 8 2 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 10 12 4 141 167 50 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 175 207 62 141 167 50 88 105 31 26 31 9 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 48 48 48 129 129 129 +215 215 215 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +215 215 215 119 119 119 27 27 27 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 38 45 13 159 189 56 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 144 171 51 12 14 4 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 14 16 5 146 173 51 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 173 206 61 135 161 48 +77 92 27 17 20 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 42 42 42 129 129 129 215 215 215 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 238 238 238 154 154 154 60 60 60 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 58 69 20 170 202 60 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 149 178 53 16 19 6 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 16 19 6 149 178 53 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 169 201 60 124 147 44 65 77 23 10 12 4 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +42 42 42 133 133 133 219 219 219 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 249 249 249 176 176 176 80 80 80 6 6 6 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 1 0 82 98 29 175 207 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 152 180 53 18 21 6 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 21 25 8 155 184 54 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +151 179 53 100 119 35 49 59 17 5 6 2 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 27 27 27 110 110 110 208 208 208 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +215 215 215 119 119 119 21 21 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 7 2 +114 135 40 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 155 184 54 21 25 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 21 25 8 152 180 53 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 172 204 61 129 153 45 78 93 27 26 31 9 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 17 17 17 93 93 93 187 187 187 254 254 254 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 222 222 222 143 143 143 48 48 48 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23 27 8 139 166 49 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +151 179 53 21 25 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 20 6 +144 171 51 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 162 192 57 111 132 39 59 70 21 10 12 4 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 8 8 +84 84 84 180 180 180 249 249 249 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 238 238 238 161 161 161 66 66 66 1 1 1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 55 65 19 164 195 58 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 148 175 52 +19 22 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +14 17 5 143 169 50 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 157 187 55 114 135 40 75 89 26 +32 38 11 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 77 77 77 161 161 161 242 242 242 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 246 246 246 +180 180 180 84 84 84 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 4 5 1 100 119 35 175 208 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 141 168 50 14 16 5 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 11 13 4 136 161 48 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +175 207 62 144 171 51 103 122 36 63 75 22 21 25 7 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 2 2 2 66 66 66 157 157 157 238 238 238 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 252 252 250 180 180 180 93 93 93 13 13 13 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 23 27 8 139 166 49 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 135 161 48 10 12 4 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 8 9 3 121 144 43 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 168 199 59 103 122 36 86 102 30 +127 151 45 168 200 59 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 175 207 62 151 179 53 119 142 42 87 103 31 51 61 18 +11 13 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 42 42 42 +129 129 129 222 222 222 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 208 208 208 110 110 110 24 24 24 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 67 79 24 165 196 58 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 120 143 42 7 8 2 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 2 2 1 100 119 35 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 115 137 41 +13 16 5 3 4 1 39 46 14 75 89 26 103 122 36 129 153 45 157 187 55 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 166 197 58 144 171 51 118 140 42 +92 110 32 66 78 23 38 45 13 8 10 3 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 42 42 42 129 129 129 219 219 219 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 254 254 254 198 198 198 +114 114 114 34 34 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 19 23 7 +125 149 44 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 99 117 35 1 2 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 92 27 174 207 61 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +159 189 56 56 66 20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 11 3 +37 43 13 54 64 19 66 78 23 77 92 27 90 107 32 101 120 35 112 134 40 120 143 42 +117 139 41 117 139 41 117 139 41 114 135 40 105 125 37 105 125 37 103 122 36 90 107 32 +77 92 27 63 75 22 49 59 17 28 34 10 9 11 3 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 27 27 27 110 110 110 198 198 198 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 252 252 252 198 198 198 110 110 110 27 27 27 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 71 84 25 166 198 59 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 174 207 61 75 89 26 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 55 65 19 169 201 60 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 121 144 43 19 23 7 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 21 21 21 105 106 101 +190 190 190 252 252 252 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +246 246 246 183 183 183 99 99 99 21 21 21 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 21 25 8 129 153 45 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +168 200 59 54 64 19 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 32 38 11 +153 181 54 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 167 198 59 77 92 27 3 3 1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 13 13 13 88 88 88 180 180 180 249 249 249 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 231 231 231 154 154 154 80 80 80 +10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 6 7 2 86 102 30 169 201 60 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 152 180 53 +32 38 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +10 11 3 121 144 43 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 149 178 53 51 61 18 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +10 10 10 77 77 77 161 161 161 242 242 242 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 215 215 215 133 133 133 60 60 60 1 1 1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 54 64 19 153 182 54 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 125 149 44 12 14 4 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 1 2 0 89 106 31 175 207 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 121 144 43 +25 30 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 17 17 99 99 99 180 180 180 +249 249 249 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 222 222 222 157 157 157 +88 88 88 21 21 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 32 38 11 +131 156 46 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 175 207 62 88 104 31 1 2 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 52 62 18 164 195 58 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +173 205 61 103 122 36 17 20 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 34 34 34 110 110 110 187 187 187 249 249 249 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 234 234 234 169 169 169 99 99 99 34 34 34 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 19 23 7 105 125 37 174 207 61 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 164 195 58 51 61 18 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 19 23 7 131 156 46 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 169 201 60 94 111 33 12 14 4 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 53 53 53 +133 133 133 208 208 208 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 222 222 222 161 161 161 +110 110 110 48 48 48 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 19 23 7 103 122 36 172 204 61 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 130 154 46 19 22 7 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 77 92 27 172 204 61 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 168 199 59 100 119 35 18 21 6 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 17 17 17 84 84 84 154 154 154 231 231 231 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 246 246 246 194 194 194 139 139 139 80 80 80 24 24 24 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 19 23 7 100 119 35 170 202 60 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +173 206 61 88 105 31 1 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 35 42 12 +149 178 53 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 170 202 60 101 120 35 +21 25 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 +60 60 60 129 129 129 198 198 198 252 252 252 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 234 234 234 187 187 187 143 143 143 99 99 99 +53 53 53 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 26 31 9 +104 124 37 172 204 61 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 148 175 52 +35 41 12 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +8 9 3 100 119 35 175 207 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +173 206 61 117 139 41 41 48 14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 3 3 3 48 48 48 110 110 110 180 180 180 242 242 242 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 231 231 231 198 198 198 +161 161 161 114 114 114 71 71 71 24 24 24 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 1 2 0 51 61 18 125 149 44 175 208 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 175 207 62 99 117 35 7 8 2 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 39 46 14 146 173 51 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 141 167 50 66 78 23 7 8 2 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 13 13 13 +71 71 71 129 129 129 187 187 187 242 242 242 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 241 241 241 222 222 222 198 198 198 +169 169 169 139 139 139 105 106 101 74 74 74 42 42 42 8 8 8 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 10 12 4 77 92 27 151 179 53 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 146 173 51 38 45 13 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 4 5 1 87 103 31 171 203 60 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 166 197 58 104 124 37 37 43 13 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 71 71 71 114 114 114 +119 119 119 124 124 124 119 119 119 119 119 119 119 119 119 119 119 119 105 106 101 88 88 88 +71 71 71 53 53 53 37 37 37 21 21 21 3 3 3 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 0 +44 52 15 108 128 38 167 198 59 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 171 203 60 86 102 30 3 4 1 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 28 34 10 133 157 47 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +144 171 51 84 99 29 23 27 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 32 38 11 95 113 33 156 185 55 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 131 156 46 28 33 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 70 21 +154 183 54 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 175 208 62 138 164 48 77 92 27 23 27 8 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 28 34 10 82 98 29 144 171 51 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 153 182 54 +58 69 20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +6 7 2 86 102 30 168 200 59 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 146 173 51 92 110 32 +39 46 14 2 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 8 2 51 61 18 +103 122 36 154 183 54 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 168 199 59 84 99 29 6 7 2 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 19 22 7 111 132 39 174 207 61 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 165 196 58 121 144 43 75 89 26 28 34 10 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 3 4 1 37 43 13 77 92 27 125 149 44 170 202 60 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 174 207 61 109 129 38 18 21 6 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 28 34 10 117 139 41 175 207 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 162 193 57 124 147 44 86 102 30 +47 55 16 10 11 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 20 6 55 65 19 +95 113 33 134 159 47 170 202 60 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 175 207 62 115 137 41 28 33 10 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 32 38 11 121 144 43 +175 208 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 175 208 62 153 181 54 121 144 43 89 106 31 58 69 20 31 37 11 6 7 2 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +14 16 5 44 52 15 71 84 25 99 117 35 127 151 45 155 184 54 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 175 208 62 +121 144 43 31 37 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +37 43 13 120 143 42 175 207 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +157 187 55 133 157 47 111 132 39 92 110 32 76 90 27 58 69 20 41 48 14 28 33 10 +17 20 6 7 8 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 4 1 12 14 4 18 21 6 +35 41 12 51 61 18 67 79 24 86 102 30 101 120 35 119 142 42 135 161 48 163 193 57 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 175 207 62 119 142 42 35 42 12 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 25 30 9 104 124 37 170 202 60 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 173 205 61 164 195 58 160 190 56 153 181 54 153 181 54 152 180 53 +153 181 54 159 189 56 164 195 58 169 201 60 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 169 201 60 103 122 36 25 30 9 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 14 16 5 82 98 29 159 189 56 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 162 192 57 94 111 33 17 20 6 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 6 2 59 70 21 +129 153 45 175 208 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 141 167 50 +71 84 25 7 8 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 25 30 9 88 105 31 156 185 55 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 159 189 56 100 119 35 30 35 10 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 3 4 1 55 65 19 115 137 41 168 200 59 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 168 199 59 114 135 40 55 65 19 3 4 1 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 7 2 54 64 19 +111 132 39 168 199 59 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 170 202 60 124 147 44 +65 77 23 8 10 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 9 11 3 59 70 21 111 132 39 159 189 56 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 159 189 56 109 129 38 59 70 21 8 10 3 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 30 35 10 82 98 29 129 153 45 +172 204 61 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 174 207 61 +141 167 50 94 111 33 41 49 15 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +8 9 3 41 49 15 82 98 29 124 147 44 164 195 58 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 168 200 59 135 161 48 94 111 33 54 64 19 11 13 4 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 3 3 1 35 41 12 75 89 26 106 126 37 +138 164 48 168 199 59 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 168 199 59 138 164 48 +106 126 37 75 89 26 35 41 12 2 2 1 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 1 2 0 24 29 9 57 67 20 86 102 30 111 132 39 134 159 47 157 187 55 +175 207 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 +176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 176 209 62 175 207 62 +156 185 55 134 159 47 111 132 39 86 102 30 56 66 20 24 29 9 1 1 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +4 5 1 25 30 9 49 59 17 66 78 23 78 93 27 92 110 32 108 128 38 120 143 42 +134 159 47 146 173 51 153 181 54 153 181 54 163 193 57 164 195 58 168 199 59 176 209 62 +176 209 62 168 199 59 164 195 58 163 193 57 153 181 54 153 181 54 146 173 51 133 157 47 +120 143 42 108 128 38 92 110 32 78 93 27 66 78 23 49 59 17 25 30 9 4 5 1 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +P3 +63 80 +255 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 0 +0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 +0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 +10 15 3 2 3 1 12 18 4 42 61 14 19 27 6 11 16 4 +38 55 13 10 15 3 3 4 1 10 15 3 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 1 +12 18 4 1 1 0 23 34 8 31 45 11 10 15 3 32 47 11 +34 49 12 3 4 1 3 4 1 3 4 1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 10 15 3 29 42 10 26 37 9 12 18 4 +55 80 19 81 118 28 55 80 19 92 132 31 106 153 36 69 100 23 +100 144 34 80 116 27 42 61 14 81 118 28 23 34 8 27 40 9 +15 21 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 1 1 0 29 42 10 15 21 5 50 72 17 +74 107 25 45 64 15 102 148 35 80 116 27 84 121 28 111 160 38 +69 100 23 65 94 22 81 118 28 29 42 10 17 25 6 29 42 10 +23 34 8 2 3 1 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 4 1 +15 21 5 15 21 5 34 49 12 101 146 34 111 161 38 97 141 33 +97 141 33 119 172 41 117 170 40 116 167 40 118 170 40 118 171 40 +117 169 40 118 170 40 111 160 38 118 170 40 96 138 32 89 128 30 +81 118 28 11 16 4 10 15 3 1 1 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +3 4 1 3 4 1 34 49 12 101 146 34 79 115 27 111 160 38 +114 165 39 113 163 39 118 170 40 117 169 40 118 171 40 117 169 40 +116 167 40 119 172 41 113 163 39 92 132 31 105 151 36 113 163 39 +75 109 26 19 27 6 16 23 5 11 16 4 0 1 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 15 3 +80 116 27 106 153 36 105 151 36 114 165 39 118 170 40 118 171 40 +118 171 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 170 40 117 169 40 118 170 40 118 170 40 +117 170 40 75 109 26 75 109 26 34 49 12 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 4 1 +64 92 22 65 94 22 100 144 34 118 171 40 118 170 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 118 171 41 118 170 40 117 169 40 +109 158 37 105 151 36 104 150 35 47 69 16 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +42 61 14 115 167 39 118 170 40 117 169 40 117 169 40 117 169 40 +117 170 40 117 170 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 118 170 40 96 138 32 17 25 6 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 47 69 16 +114 165 39 117 168 40 117 170 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 118 170 40 117 169 40 117 169 40 117 169 40 +117 170 40 119 172 41 96 138 32 12 18 4 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 15 3 +32 47 11 105 151 36 118 170 40 117 169 40 117 169 40 116 168 40 +109 157 37 111 160 38 117 169 40 118 171 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 118 171 40 69 100 23 2 3 1 +0 0 0 0 0 0 0 0 0 0 0 0 19 27 6 101 146 34 +118 171 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 170 40 +118 171 40 115 166 39 107 154 36 111 161 38 117 169 40 117 169 40 +117 169 40 118 171 40 75 109 26 19 27 6 2 3 1 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 16 23 5 +89 128 30 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +111 160 38 92 132 31 79 115 27 96 138 32 115 166 39 119 171 41 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 118 170 40 109 157 37 26 37 9 +0 0 0 0 0 0 0 0 0 0 0 0 64 92 22 118 171 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 118 170 40 118 171 40 109 157 37 +89 128 30 81 118 28 100 144 34 115 166 39 117 169 40 117 169 40 +117 169 40 117 170 40 113 163 39 60 86 20 1 1 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +27 40 9 96 138 32 118 170 40 117 169 40 117 169 40 117 169 40 +117 170 40 117 169 40 101 146 34 67 96 23 55 80 19 84 121 28 +113 163 39 119 171 41 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 119 171 41 65 94 22 +0 0 0 0 0 0 0 0 0 15 21 5 101 146 34 118 171 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 118 170 40 118 171 40 104 150 35 69 100 23 53 76 18 +81 118 28 111 160 38 118 170 40 117 169 40 117 169 40 117 169 40 +117 169 40 114 165 39 69 100 23 10 15 3 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 +31 45 11 77 111 26 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 118 170 40 116 168 40 92 132 31 47 69 16 +38 55 13 81 118 28 113 163 39 119 171 41 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 118 171 41 92 132 31 +10 15 3 0 0 0 0 0 0 36 52 12 115 166 39 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 118 170 40 +118 171 40 102 148 35 64 92 22 34 49 12 65 94 22 106 153 36 +118 171 40 117 170 40 117 169 40 117 169 40 117 169 40 117 169 40 +118 170 40 107 154 36 55 80 19 15 21 5 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +29 42 10 101 146 34 118 171 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 118 171 40 113 163 39 +75 109 26 27 40 9 36 52 12 89 128 30 116 167 40 118 171 40 +117 169 40 117 169 40 117 169 40 117 169 40 118 170 40 104 150 35 +16 23 5 0 0 0 0 0 0 53 76 18 118 171 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 119 171 41 109 157 37 +67 96 23 23 34 8 42 61 14 96 138 32 118 170 40 118 170 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 74 107 25 10 15 3 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 31 45 11 101 146 34 118 170 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +119 171 41 102 148 35 47 69 16 14 20 5 50 72 17 102 148 35 +118 171 40 117 169 40 117 169 40 117 169 40 118 170 40 102 148 35 +15 21 5 0 0 0 0 0 0 50 72 17 118 170 40 117 169 40 +117 169 40 117 169 40 118 170 40 116 167 40 84 121 28 27 40 9 +19 27 6 74 107 25 114 165 39 118 171 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 75 109 26 10 15 4 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 38 55 13 102 148 35 118 171 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 118 170 40 115 167 39 77 111 26 17 25 6 19 27 6 +77 111 26 115 166 39 118 170 40 117 169 40 119 172 41 81 118 28 +3 4 1 0 0 0 0 0 0 27 40 9 111 160 38 118 170 40 +117 169 40 118 171 40 105 151 36 50 72 17 10 15 3 38 55 13 +100 144 34 118 171 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 79 115 27 15 21 5 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 10 15 3 64 92 22 111 160 38 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 118 171 40 96 138 32 32 47 11 +3 4 1 50 72 17 107 154 36 120 173 41 105 151 36 31 45 11 +0 0 0 0 0 0 0 0 0 3 4 1 65 94 22 117 169 40 +118 170 40 89 128 30 26 37 9 3 4 1 60 86 20 111 161 38 +118 171 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +97 141 33 36 52 12 1 1 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 14 20 5 75 109 26 117 168 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 118 171 40 107 154 36 +45 64 15 2 3 1 31 45 11 75 109 26 32 47 11 0 1 0 +0 0 0 0 0 0 0 0 0 0 0 0 10 15 3 55 80 19 +65 94 22 11 16 4 11 16 4 75 109 26 116 168 40 118 170 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 118 170 40 107 154 36 +47 69 16 3 4 1 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 12 18 4 69 100 23 111 161 38 118 171 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 118 170 40 +111 160 38 50 72 17 2 3 1 2 3 1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 +1 1 0 12 18 4 81 118 28 118 170 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 170 40 118 171 40 101 146 34 +42 61 14 2 3 1 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 3 4 1 36 52 12 89 128 30 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +118 171 41 101 146 34 14 20 5 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 47 69 16 118 170 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 170 40 111 160 38 69 100 23 19 27 6 +0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 11 16 4 69 100 23 +115 167 39 119 172 41 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +119 172 41 75 109 26 3 4 1 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 23 34 8 106 153 36 118 170 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 118 170 40 119 172 41 105 151 36 42 61 14 2 3 1 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 15 21 5 +45 64 15 80 116 27 114 165 39 118 170 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 119 172 41 +97 141 33 20 30 7 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 1 1 0 53 76 18 114 165 39 118 171 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +118 171 40 104 150 35 64 92 22 31 45 11 10 15 3 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 36 52 12 97 141 33 109 158 37 113 163 39 116 168 40 +117 169 40 117 170 40 118 170 40 119 172 41 115 167 39 84 121 28 +23 34 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 3 4 1 50 72 17 102 148 35 118 171 40 +119 171 41 118 170 40 117 169 40 117 169 40 115 166 39 111 161 38 +109 157 37 79 115 27 12 18 4 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 3 4 1 15 21 5 23 34 8 45 64 15 106 153 36 +116 167 40 111 160 38 101 146 34 79 115 27 42 61 14 10 15 3 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 1 1 0 20 30 7 60 86 20 +89 128 30 106 153 36 113 163 39 117 169 40 84 121 28 29 42 10 +19 27 6 10 15 3 2 3 1 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 16 23 5 38 55 13 +36 52 12 26 37 9 12 18 4 2 3 1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 1 0 0 19 2 7 52 5 18 +78 7 27 88 8 31 81 7 29 56 5 19 25 2 9 3 0 1 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +3 4 1 19 27 6 31 45 11 38 55 13 32 47 11 3 4 1 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 1 +9 0 3 12 1 4 9 0 3 4 0 1 0 0 0 0 0 0 +0 0 0 0 0 0 28 3 10 99 9 35 156 14 55 182 16 64 +189 17 66 190 17 67 189 17 66 184 17 65 166 15 58 118 13 41 +45 4 16 3 0 1 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 11 1 4 52 5 18 101 9 35 134 12 47 +151 14 53 154 14 54 151 14 53 113 10 40 11 1 4 0 0 0 +3 0 1 67 6 24 159 14 56 190 17 67 190 17 67 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 191 17 67 +174 16 61 101 9 35 14 1 5 0 0 0 35 3 12 108 10 38 +122 11 43 122 11 43 112 10 39 87 8 30 50 5 17 13 1 5 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +3 0 1 56 5 19 141 13 49 182 16 64 191 17 67 191 17 67 +190 17 67 190 17 67 191 17 67 113 10 40 3 0 1 1 0 0 +79 7 28 180 16 63 190 17 67 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +189 17 66 188 17 66 122 11 43 11 1 4 41 4 14 176 16 62 +191 17 67 191 17 67 191 17 67 190 17 67 181 16 63 146 13 51 +75 7 26 10 1 4 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 1 2 +90 8 32 178 16 62 191 17 67 188 17 66 188 17 66 188 17 66 +188 17 66 190 17 67 141 13 49 22 2 8 0 0 0 41 4 14 +173 16 61 190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 88 8 31 1 0 0 89 8 31 +185 17 65 189 17 66 188 17 66 188 17 66 189 17 66 191 17 67 +186 17 65 124 11 43 25 2 9 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 2 0 1 89 8 31 +184 17 65 189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +190 17 67 151 14 53 34 3 12 0 0 0 0 0 0 79 7 28 +190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 191 17 67 146 13 51 9 1 3 7 1 2 +108 10 38 187 17 66 189 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 190 17 67 141 13 49 22 2 8 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 52 5 18 176 16 62 +189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 +151 14 53 38 3 13 0 0 0 0 0 0 0 0 0 50 5 17 +180 16 63 189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 191 17 67 141 13 49 7 1 3 0 0 0 +11 1 4 112 10 39 187 17 66 189 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 190 17 67 113 10 40 5 0 2 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 7 1 3 132 12 46 191 17 67 +188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 146 13 51 +35 3 12 0 0 0 0 0 0 0 0 0 0 0 0 5 0 2 +101 9 35 185 17 65 190 17 67 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 190 17 67 180 16 63 67 6 24 0 0 0 0 0 0 +0 0 0 11 1 4 108 10 38 186 17 65 189 17 66 188 17 66 +188 17 66 188 17 66 189 17 66 180 16 63 56 5 19 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 44 4 15 177 16 62 189 17 66 +188 17 66 188 17 66 189 17 66 189 17 66 134 12 47 28 3 10 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +8 1 3 79 7 28 159 14 56 188 17 66 191 17 67 190 17 67 +189 17 66 189 17 66 189 17 66 189 17 66 190 17 67 191 17 67 +188 17 66 158 14 55 72 7 25 4 0 1 0 0 0 0 0 0 +0 0 0 0 0 0 8 1 3 95 9 33 182 16 64 189 17 67 +188 17 66 188 17 66 188 17 66 191 17 67 122 11 43 3 0 1 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 88 8 31 190 17 67 188 17 66 +188 17 66 189 17 66 185 17 65 113 10 40 18 2 6 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 1 0 0 24 2 8 77 7 27 124 11 43 154 14 54 +168 15 59 173 16 61 173 16 61 168 15 59 154 14 54 124 11 43 +77 7 27 22 2 8 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 5 0 2 77 7 27 173 16 61 +190 17 67 188 17 66 188 17 66 190 17 67 164 15 57 23 2 8 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 1 0 0 118 13 41 191 17 67 188 17 66 +190 17 67 174 16 61 87 8 30 8 1 3 0 0 0 0 0 0 +0 0 0 0 0 0 10 1 4 29 3 10 40 4 14 36 3 13 +18 2 6 2 0 1 0 0 0 0 0 0 3 0 1 14 1 5 +26 2 9 33 3 11 32 3 11 25 2 9 13 1 5 3 0 1 +0 0 0 14 1 5 56 5 19 95 9 33 109 10 38 101 9 35 +77 7 27 35 3 12 5 0 2 0 0 0 1 0 0 56 5 19 +156 14 55 190 17 67 188 17 66 188 17 66 182 16 64 50 5 17 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 5 0 2 134 12 47 191 17 67 189 17 66 +151 14 53 52 5 18 2 0 1 0 0 0 0 0 0 1 0 0 +28 3 10 90 8 32 146 13 51 170 15 60 178 16 62 174 16 61 +158 14 55 112 10 39 40 4 14 1 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 1 +56 5 19 146 13 51 183 17 64 191 17 67 191 17 67 191 17 67 +188 17 66 173 16 61 122 11 43 41 4 14 1 0 0 0 0 0 +30 3 10 124 11 43 185 17 65 190 17 67 187 17 66 67 6 24 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 6 1 2 134 12 47 168 15 59 99 9 35 +21 2 7 0 0 0 0 0 0 0 0 0 6 1 2 77 7 27 +162 15 57 190 17 67 191 17 67 189 17 66 189 17 66 189 17 66 +190 17 67 191 17 67 169 15 59 75 7 26 3 0 1 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 2 0 1 79 7 28 +178 16 62 191 17 67 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 189 17 66 191 17 67 170 15 60 79 7 28 5 0 2 +0 0 0 10 1 3 78 7 27 159 14 56 188 17 66 75 7 26 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 1 0 0 35 3 12 29 3 10 2 0 1 +0 0 0 0 0 0 0 0 0 9 1 3 101 9 35 183 17 64 +190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 190 17 67 178 16 63 67 6 23 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 52 5 18 174 16 61 +190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 190 17 67 182 16 64 89 8 31 +4 0 1 0 0 0 0 0 0 25 2 9 73 7 26 31 3 11 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 4 0 1 98 9 34 187 17 66 189 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 190 17 67 158 14 55 25 2 9 +0 0 0 0 0 0 0 0 0 8 1 3 134 12 47 191 17 67 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 189 17 66 180 16 63 +68 6 24 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 6 1 2 19 2 7 3 0 1 0 0 0 0 0 0 +0 0 0 0 0 0 65 6 23 180 16 63 189 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 189 17 66 83 8 29 +0 0 0 0 0 0 0 0 0 41 4 14 177 16 62 189 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 +159 14 56 28 3 10 0 0 0 0 0 0 0 0 0 23 2 8 +41 4 14 5 0 2 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +23 2 8 113 10 40 159 14 56 65 6 23 0 0 0 0 0 0 +0 0 0 16 1 6 146 13 51 191 17 67 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 191 17 67 132 12 46 +5 0 2 0 0 0 0 0 0 77 7 27 189 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +190 17 67 98 9 34 0 0 0 0 0 0 12 1 4 134 12 47 +178 16 63 108 10 38 16 1 6 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 30 3 10 +141 13 49 190 17 67 191 17 67 134 12 47 6 1 2 0 0 0 +0 0 0 68 6 24 186 17 65 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 156 14 55 +14 1 5 0 0 0 0 0 0 98 9 34 191 17 67 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +190 17 67 156 14 55 19 2 7 0 0 0 47 4 16 181 16 63 +190 17 67 189 17 66 126 14 44 17 2 6 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 16 1 6 134 12 47 +191 17 67 188 17 66 190 17 67 162 15 57 19 2 7 0 0 0 +3 0 1 123 11 43 191 17 67 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 163 15 57 +20 2 7 0 0 0 0 0 0 101 9 35 191 17 67 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 182 16 64 52 5 18 0 0 0 73 7 26 188 17 66 +188 17 66 188 17 66 189 17 66 109 10 38 5 0 2 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 95 9 33 189 17 66 +188 17 66 188 17 66 189 17 66 171 15 60 29 3 10 0 0 0 +16 1 6 156 14 55 190 17 67 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 158 14 55 +17 2 6 0 0 0 0 0 0 85 8 30 190 17 67 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 189 17 66 81 7 29 0 0 0 85 8 30 190 17 67 +188 17 66 188 17 66 189 17 66 180 16 63 56 5 19 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 25 2 9 162 15 57 190 17 67 +188 17 66 188 17 66 189 17 66 173 16 61 31 3 11 0 0 0 +30 3 10 171 15 60 189 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 191 17 67 141 13 49 +7 1 2 0 0 0 0 0 0 56 5 19 183 17 64 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 191 17 67 98 9 34 0 0 0 88 8 31 190 17 67 +188 17 66 188 17 66 188 17 66 191 17 67 124 11 43 5 0 2 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 68 6 24 187 17 66 188 17 66 +188 17 66 188 17 66 189 17 66 170 15 60 28 3 10 0 0 0 +34 3 12 174 16 61 189 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 191 17 67 101 9 35 +0 0 0 0 0 0 0 0 0 21 2 7 159 14 56 190 17 67 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 191 17 67 98 9 34 0 0 0 81 7 29 189 17 66 +188 17 66 188 17 66 188 17 66 189 17 66 168 15 59 28 3 10 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 109 10 38 191 17 67 188 17 66 +188 17 66 188 17 66 190 17 67 163 15 57 21 2 7 0 0 0 +26 2 9 168 15 59 189 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 189 17 66 180 16 63 47 4 16 +0 0 0 0 0 0 0 0 0 0 0 0 108 10 38 190 17 67 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 189 17 66 78 7 27 0 0 0 68 6 24 187 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 183 17 64 56 5 19 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 3 0 1 131 12 46 191 17 67 188 17 66 +188 17 66 188 17 66 190 17 67 151 14 53 12 1 4 0 0 0 +11 1 4 146 13 51 190 17 67 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 191 17 67 126 14 44 7 1 2 +0 0 0 0 0 0 0 0 0 0 0 0 32 3 11 164 15 58 +190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +189 17 66 178 16 62 44 4 15 0 0 0 50 5 17 182 16 64 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 72 7 25 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 5 0 2 134 12 47 191 17 67 188 17 66 +188 17 66 188 17 66 191 17 67 131 12 46 3 0 1 0 0 0 +0 0 0 101 9 35 190 17 67 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 190 17 67 170 15 60 44 4 15 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 7 27 +183 17 64 189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +191 17 67 134 12 47 9 1 3 0 0 0 31 3 11 171 15 60 +189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 72 7 25 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 2 0 1 124 11 43 191 17 67 188 17 66 +188 17 66 188 17 66 191 17 67 101 9 35 0 0 0 0 0 0 +0 0 0 35 3 12 168 15 59 190 17 67 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 189 17 66 182 16 64 77 7 27 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 1 2 +99 9 35 185 17 65 189 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 189 17 66 +177 16 62 56 5 19 0 0 0 0 0 0 13 1 5 151 14 53 +190 17 67 188 17 66 188 17 66 188 17 66 185 17 65 56 5 19 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 99 9 35 191 17 67 188 17 66 +188 17 66 188 17 66 186 17 65 65 6 23 0 0 0 0 0 0 +0 0 0 0 0 0 79 7 28 182 16 64 190 17 67 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +191 17 67 177 16 62 83 8 29 4 0 1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +8 1 3 89 8 31 175 16 62 191 17 67 189 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 181 16 63 +85 8 30 3 0 1 0 0 0 0 0 0 1 0 0 118 13 41 +191 17 67 188 17 66 188 17 66 189 17 66 173 16 61 34 3 12 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 56 5 19 183 17 64 188 17 66 +188 17 66 189 17 66 169 15 59 30 3 10 0 0 0 0 0 0 +0 0 0 0 0 0 5 0 2 83 8 29 173 16 61 191 17 67 +190 17 67 189 17 66 189 17 66 190 17 67 191 17 67 187 17 66 +151 14 53 56 5 19 3 0 1 0 0 0 16 1 6 50 5 17 +79 7 28 95 9 33 95 9 33 75 7 26 41 4 14 10 1 4 +0 0 0 2 0 1 50 5 17 132 12 46 178 16 62 190 17 67 +191 17 67 191 17 67 191 17 67 186 17 65 154 14 54 68 6 24 +4 0 1 0 0 0 0 0 0 0 0 0 0 0 0 72 7 25 +187 17 66 188 17 66 188 17 66 191 17 67 141 13 49 9 1 3 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 14 1 5 151 14 53 190 17 67 +188 17 66 191 17 67 131 12 46 5 0 2 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 2 0 1 44 4 15 113 10 40 +156 14 55 173 16 61 174 16 61 164 15 58 134 12 47 77 7 27 +18 2 6 0 0 0 16 1 6 85 8 30 151 14 53 182 16 64 +189 17 66 191 17 67 190 17 67 188 17 66 177 16 62 141 13 49 +68 6 24 8 1 3 0 0 0 8 1 3 44 4 15 88 8 31 +113 10 40 122 11 43 108 10 38 67 6 24 20 2 7 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 28 3 10 +166 15 58 190 17 67 188 17 66 187 17 66 79 7 28 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 73 7 26 185 17 65 +189 17 66 184 17 65 65 6 23 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 1 +17 2 6 32 3 11 34 3 12 22 2 8 6 1 2 0 0 0 +0 0 0 38 3 13 141 13 49 188 17 66 190 17 67 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 189 17 66 191 17 67 +184 17 65 122 11 43 21 2 7 0 0 0 0 0 0 0 0 0 +0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 +108 10 38 191 17 67 191 17 67 141 13 49 16 1 6 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 8 1 3 112 10 39 +186 17 65 124 11 43 10 1 4 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +36 3 13 156 14 55 191 17 67 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +189 17 66 190 17 67 134 12 47 18 2 6 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 7 1 2 41 4 14 75 7 26 66 5 23 19 2 7 +26 2 9 144 13 50 154 14 54 40 4 14 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 13 1 5 +56 5 19 19 2 7 0 0 0 7 1 2 29 3 10 35 3 12 +19 2 7 2 0 1 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 13 1 5 +134 12 47 191 17 67 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 189 17 67 108 10 38 3 0 1 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 +40 4 14 124 11 43 177 16 62 188 17 66 187 17 66 144 13 50 +24 2 8 17 2 6 22 2 8 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 19 2 7 122 11 43 171 15 60 175 16 62 +159 14 56 112 10 39 40 4 14 2 0 1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 72 7 25 +186 17 65 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 189 17 66 174 16 61 41 4 14 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 3 0 1 72 7 25 +168 15 59 191 17 67 189 17 66 188 17 66 188 17 66 190 17 67 +95 9 33 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 95 9 33 191 17 67 189 17 66 189 17 66 +190 17 67 191 17 67 171 15 60 90 8 32 12 1 4 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 5 0 2 132 12 46 +191 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 190 17 67 98 9 34 0 0 0 +0 0 0 0 0 0 0 0 0 5 0 2 88 8 31 180 16 63 +190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 191 17 67 +146 13 51 11 1 4 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 9 1 3 144 13 50 191 17 67 188 17 66 188 17 66 +188 17 66 188 17 66 189 17 66 187 17 66 123 11 43 20 2 7 +0 0 0 0 0 0 0 0 0 0 0 0 21 2 7 163 15 57 +190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 191 17 67 134 12 47 5 0 2 +0 0 0 0 0 0 3 0 1 88 8 31 182 16 64 189 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 189 17 66 +171 15 60 31 3 11 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 20 2 7 162 15 57 190 17 67 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 132 12 46 +20 2 7 0 0 0 0 0 0 0 0 0 32 3 11 173 16 61 +189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 190 17 67 151 14 53 12 1 4 +0 0 0 0 0 0 72 7 25 180 16 63 189 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +181 16 63 47 4 16 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 21 2 7 163 15 57 190 17 67 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 +122 11 43 9 1 3 0 0 0 0 0 0 30 3 10 171 15 60 +189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 190 17 67 146 13 51 10 1 4 +0 0 0 38 3 13 166 15 58 190 17 67 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +183 17 64 52 5 18 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 13 1 5 154 14 54 190 17 67 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +186 17 65 79 7 28 0 0 0 0 0 0 14 1 5 156 14 54 +190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 191 17 67 124 11 43 2 0 1 +5 0 2 122 11 43 191 17 67 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +182 16 64 47 4 16 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 3 0 1 126 14 44 191 17 67 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +190 17 67 158 14 55 23 2 8 0 0 0 1 0 0 113 10 40 +191 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 78 7 27 0 0 0 +47 4 16 177 16 62 189 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 189 17 66 +173 16 61 34 3 12 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 85 8 30 189 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 79 7 28 0 0 0 0 0 0 47 4 16 +175 16 62 189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 190 17 67 156 14 55 22 2 8 0 0 0 +109 10 38 191 17 67 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 +151 14 53 13 1 5 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 35 3 12 173 16 61 189 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 191 17 67 134 12 47 7 1 2 0 0 0 3 0 1 +99 9 35 188 17 66 189 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 189 17 66 181 16 63 68 6 24 0 0 0 18 2 6 +156 14 55 190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 +101 9 35 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 3 0 1 118 13 41 191 17 67 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 189 17 66 168 15 59 28 3 10 0 0 0 0 0 0 +12 1 4 113 10 40 187 17 66 189 17 67 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +190 17 67 180 16 63 88 8 31 4 0 1 0 0 0 47 4 16 +180 16 63 189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 168 15 59 +36 3 13 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 38 3 13 164 15 58 190 17 67 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 182 16 64 50 5 17 0 0 0 0 0 0 +0 0 0 11 1 4 90 8 32 169 15 59 190 17 67 190 17 67 +189 17 66 189 17 66 189 17 66 189 17 66 191 17 67 189 17 66 +158 14 55 68 6 24 4 0 1 0 0 0 0 0 0 73 7 26 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 189 17 66 185 17 65 83 8 29 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 65 6 23 174 16 61 +190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 185 17 65 56 5 19 0 0 0 0 0 0 +0 0 0 0 0 0 2 0 1 35 3 12 99 9 35 146 13 51 +170 15 60 177 16 62 177 16 62 166 15 58 141 13 49 85 8 30 +24 2 8 0 0 0 0 0 0 0 0 0 0 0 0 85 8 30 +190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 189 17 66 112 10 39 8 1 3 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 68 6 24 +170 15 60 191 17 67 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 182 16 64 50 5 17 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 11 1 4 +28 3 10 40 4 14 38 3 13 25 2 9 8 1 3 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 78 7 27 +189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 189 17 66 187 17 66 113 10 40 14 1 5 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 +47 4 16 141 13 49 186 17 65 191 17 67 190 17 67 189 17 66 +189 17 66 191 17 67 156 14 55 20 2 7 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 44 4 15 +178 16 62 190 17 67 188 17 66 188 17 66 188 17 66 190 17 67 +191 17 67 173 16 61 90 8 32 10 1 4 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 14 1 5 68 6 24 131 12 46 162 15 57 174 16 61 +171 15 60 146 13 51 56 5 19 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 3 0 1 14 1 5 29 3 10 +41 4 14 47 4 16 50 5 17 45 4 16 34 3 12 18 2 6 +5 0 2 0 0 0 0 0 0 0 0 0 0 0 0 5 0 2 +90 8 32 169 15 59 185 17 65 187 17 66 182 16 64 163 15 57 +113 10 40 41 4 14 2 0 1 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 5 0 2 21 2 7 34 3 12 +29 3 10 11 1 4 0 0 0 0 0 0 0 0 0 0 0 0 +3 0 1 32 3 11 79 7 28 124 11 43 154 14 54 171 15 60 +180 16 63 182 16 64 182 16 64 180 16 63 174 16 61 159 14 56 +132 12 46 88 8 31 34 3 12 3 0 1 0 0 0 0 0 0 +3 0 1 29 3 10 56 5 19 65 6 23 50 5 17 23 2 8 +3 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 2 9 +109 10 38 169 15 59 189 17 66 191 17 67 190 17 67 189 17 66 +189 17 66 188 17 66 188 17 66 188 17 66 189 17 66 190 17 67 +191 17 67 190 17 67 171 15 60 98 9 34 10 1 3 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 14 1 5 141 13 49 +191 17 67 189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 189 17 67 186 17 65 65 6 23 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 23 2 8 166 15 58 +190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 189 17 66 176 16 62 45 4 16 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 83 8 29 +183 17 64 189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 189 17 66 185 17 65 95 9 33 3 0 1 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 2 +85 8 30 176 16 62 191 17 67 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +191 17 67 180 16 63 95 9 33 7 1 3 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +2 0 1 52 5 18 141 13 49 185 17 65 191 17 67 189 17 67 +189 17 66 188 17 66 188 17 66 189 17 66 191 17 67 187 17 66 +146 13 51 56 5 19 4 0 1 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 14 1 5 68 6 24 131 12 46 166 15 58 +180 16 63 183 17 64 180 16 63 168 15 59 134 12 47 75 7 26 +17 2 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 5 0 2 24 2 8 +44 4 15 52 5 18 45 4 16 26 2 9 6 1 2 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 diff --git a/bsp/spacemit/dm/graphic/logo/logo-spacemit-clut224.ppm b/bsp/spacemit/dm/graphic/logo/logo-spacemit-clut224.ppm new file mode 100644 index 000000000000..785f464fa916 --- /dev/null +++ b/bsp/spacemit/dm/graphic/logo/logo-spacemit-clut224.ppm @@ -0,0 +1,1227 @@ +P3 +188 51 +255 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +2 3 1 67 81 36 123 144 74 87 104 46 2 3 1 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 1 67 81 36 +163 196 87 192 231 103 192 231 103 192 231 103 108 127 67 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 2 2 1 67 81 36 163 196 87 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 159 192 85 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 1 1 0 60 70 37 154 186 83 192 231 103 192 231 103 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 163 196 87 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 49 59 26 154 186 83 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 163 196 87 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 60 70 37 +154 186 83 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 163 196 87 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 108 127 67 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 163 196 87 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 20 10 190 229 102 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 163 196 87 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 37 44 20 192 231 103 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 163 196 87 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 37 44 20 192 231 103 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 163 196 87 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 54 54 54 183 183 183 +187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 +187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 +108 108 108 0 0 0 31 31 31 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 +187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 +187 187 187 187 187 187 187 187 187 187 187 187 108 108 108 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 108 108 108 186 186 186 187 187 187 187 187 187 +149 149 149 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 11 11 11 168 168 168 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 +187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 +187 187 187 187 187 187 143 143 143 0 0 0 0 0 0 146 146 146 187 187 187 187 187 187 +187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 +187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 178 178 178 0 0 0 0 0 0 +133 133 133 187 187 187 187 187 187 71 71 71 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 139 139 139 +187 187 187 187 187 187 81 81 81 0 0 0 79 79 79 195 195 195 195 195 195 153 153 153 +0 0 0 0 0 0 185 185 185 195 195 195 195 195 195 195 195 195 195 195 195 195 195 195 +195 195 195 195 195 195 195 195 195 195 195 195 195 195 195 195 195 195 195 195 195 195 195 195 +195 195 195 195 195 195 195 195 195 11 11 11 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 37 44 20 192 231 103 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 163 196 87 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 142 142 142 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +147 147 147 0 0 0 42 42 42 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 222 222 222 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 54 54 54 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 88 88 88 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 61 61 61 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 195 195 195 0 0 0 17 17 17 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 240 240 240 0 0 0 0 0 0 +181 181 181 255 255 255 255 255 255 229 229 229 17 17 17 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 79 79 79 255 255 255 +255 255 255 255 255 255 111 111 111 0 0 0 104 104 104 255 255 255 255 255 255 202 202 202 +0 0 0 0 0 0 244 244 244 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 15 15 15 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 37 44 20 192 231 103 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 163 196 87 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 143 143 143 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +147 147 147 0 0 0 42 42 42 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 225 225 225 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 178 178 178 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 209 209 209 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 64 64 64 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 195 195 195 0 0 0 19 19 19 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 240 240 240 0 0 0 0 0 0 +181 181 181 255 255 255 255 255 255 255 255 255 159 159 159 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 20 20 20 232 232 232 255 255 255 +255 255 255 255 255 255 111 111 111 0 0 0 104 104 104 255 255 255 255 255 255 202 202 202 +0 0 0 0 0 0 244 244 244 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 15 15 15 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 37 44 20 192 231 103 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 159 192 85 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 143 143 143 255 255 255 +255 255 255 199 199 199 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 +51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 +29 29 29 0 0 0 8 8 8 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 +51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 +51 51 51 115 115 115 255 255 255 255 255 255 225 225 225 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 45 45 45 254 254 254 255 255 255 255 255 255 170 170 170 255 255 255 +255 255 255 255 255 255 77 77 77 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 64 64 64 255 255 255 255 255 255 244 244 244 51 51 51 51 51 51 51 51 51 +51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 +51 51 51 51 51 51 39 39 39 0 0 0 4 5 3 51 51 51 51 51 51 51 51 51 +51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 +51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 48 48 48 0 0 0 0 0 0 +181 181 181 255 255 255 255 255 255 255 255 255 255 255 255 80 80 80 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 170 170 170 255 255 255 255 255 255 +255 255 255 255 255 255 111 111 111 0 0 0 104 104 104 255 255 255 255 255 255 202 202 202 +0 0 0 0 0 0 39 39 39 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 +61 61 61 255 255 255 255 255 255 255 255 255 85 85 85 43 43 43 43 43 43 43 43 43 +43 43 43 43 43 43 43 43 43 2 2 2 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 37 44 20 192 231 103 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 108 127 67 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 143 143 143 255 255 255 +255 255 255 185 185 185 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 80 80 80 255 255 255 255 255 255 225 225 225 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 167 167 167 255 255 255 255 255 255 230 230 230 9 9 9 203 203 203 +255 255 255 255 255 255 200 200 200 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 64 64 64 255 255 255 255 255 255 241 241 241 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +181 181 181 255 255 255 255 255 255 255 255 255 255 255 255 230 230 230 18 18 18 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 88 88 88 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 111 111 111 0 0 0 104 104 104 255 255 255 255 255 255 202 202 202 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +24 24 24 255 255 255 255 255 255 255 255 255 51 51 51 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 37 44 20 192 231 103 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 +192 231 103 192 231 103 192 231 103 123 144 74 8 9 5 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 143 143 143 255 255 255 +255 255 255 185 185 185 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 80 80 80 255 255 255 255 255 255 225 225 225 0 0 0 0 0 0 0 0 0 +0 0 0 35 35 35 251 251 251 255 255 255 255 255 255 113 113 113 0 0 0 82 82 82 +255 255 255 255 255 255 255 255 255 65 65 65 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 64 64 64 255 255 255 255 255 255 241 241 241 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +181 181 181 255 255 255 255 255 255 254 254 254 255 255 255 255 255 255 162 162 162 0 0 0 +0 0 0 0 0 0 0 0 0 21 21 21 235 235 235 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 111 111 111 0 0 0 104 104 104 255 255 255 255 255 255 202 202 202 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +24 24 24 255 255 255 255 255 255 255 255 255 51 51 51 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 37 44 20 192 231 103 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 +192 231 103 141 169 76 40 48 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 143 143 143 255 255 255 +255 255 255 204 204 204 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 +68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 +39 39 39 0 0 0 11 11 11 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 +68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 +68 68 68 125 125 125 255 255 255 255 255 255 225 225 225 0 0 0 0 0 0 0 0 0 +0 0 0 156 156 156 255 255 255 255 255 255 236 236 236 12 12 12 0 0 0 1 1 1 +209 209 209 255 255 255 255 255 255 187 187 187 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 64 64 64 255 255 255 255 255 255 241 241 241 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 67 67 67 68 68 68 68 68 68 +68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 +68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 2 2 2 0 0 0 +181 181 181 255 255 255 255 255 255 162 162 162 246 246 246 255 255 255 255 255 255 82 82 82 +0 0 0 0 0 0 0 0 0 171 171 171 255 255 255 255 255 255 204 204 204 224 224 224 +255 255 255 255 255 255 111 111 111 0 0 0 104 104 104 255 255 255 255 255 255 202 202 202 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +24 24 24 255 255 255 255 255 255 255 255 255 51 51 51 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 37 44 20 192 231 103 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 141 169 76 +40 48 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 143 143 143 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +147 147 147 0 0 0 42 42 42 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 225 225 225 0 0 0 0 0 0 0 0 0 +27 27 27 249 249 249 255 255 255 255 255 255 123 123 123 0 0 0 0 0 0 0 0 0 +92 92 92 255 255 255 255 255 255 255 255 255 57 57 57 0 0 0 0 0 0 0 0 0 +0 0 0 64 64 64 255 255 255 255 255 255 241 241 241 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 250 250 250 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 9 9 9 0 0 0 +181 181 181 255 255 255 255 255 255 124 124 124 115 115 115 255 255 255 255 255 255 231 231 231 +18 18 18 0 0 0 90 90 90 255 255 255 255 255 255 248 248 248 43 43 43 219 219 219 +255 255 255 255 255 255 111 111 111 0 0 0 104 104 104 255 255 255 255 255 255 202 202 202 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +24 24 24 255 255 255 255 255 255 255 255 255 51 51 51 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 37 44 20 192 231 103 192 231 103 +192 231 103 192 231 103 192 231 103 192 231 103 192 231 103 145 174 77 49 59 26 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 143 143 143 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +147 147 147 0 0 0 42 42 42 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 222 222 222 0 0 0 0 0 0 0 0 0 +146 146 146 255 255 255 255 255 255 241 241 241 16 16 16 0 0 0 0 0 0 0 0 0 +3 3 2 219 219 219 255 255 255 255 255 255 178 178 178 0 0 0 0 0 0 0 0 0 +0 0 0 64 64 64 255 255 255 255 255 255 241 241 241 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 250 250 250 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 9 9 9 0 0 0 +181 181 181 255 255 255 255 255 255 124 124 124 2 2 2 194 194 194 255 255 255 255 255 255 +164 164 164 21 21 21 234 234 234 255 255 255 255 255 255 113 113 113 0 0 0 219 219 219 +255 255 255 255 255 255 111 111 111 0 0 0 104 104 104 255 255 255 255 255 255 202 202 202 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +24 24 24 255 255 255 255 255 255 255 255 255 51 51 51 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 31 10 192 231 103 192 231 103 +192 231 103 192 231 103 192 231 103 141 169 76 45 54 24 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 96 96 96 170 170 170 +170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 +170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 230 230 230 255 255 255 255 255 255 +147 147 147 0 0 0 42 42 42 255 255 255 255 255 255 255 255 255 173 173 173 170 170 170 +170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 +170 170 170 170 170 170 170 170 170 170 170 170 90 90 90 0 0 0 0 0 0 21 21 21 +245 245 245 255 255 255 255 255 255 133 133 133 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 103 103 103 255 255 255 255 255 255 254 254 254 49 49 49 0 0 0 0 0 0 +0 0 0 64 64 64 255 255 255 255 255 255 241 241 241 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 250 250 250 255 255 255 255 255 255 +187 187 187 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 +170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 6 6 6 0 0 0 +181 181 181 255 255 255 255 255 255 124 124 124 0 0 0 38 38 38 246 246 246 255 255 255 +255 255 255 213 213 213 255 255 255 255 255 255 195 195 195 2 2 2 0 0 0 219 219 219 +255 255 255 255 255 255 111 111 111 0 0 0 104 104 104 255 255 255 255 255 255 202 202 202 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +24 24 24 255 255 255 255 255 255 255 255 255 51 51 51 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 123 144 74 192 231 103 +192 231 103 145 174 77 45 54 24 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 181 181 181 255 255 255 255 255 255 +147 147 147 0 0 0 42 42 42 255 255 255 255 255 255 255 255 255 8 8 8 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 135 135 135 +255 255 255 255 255 255 245 245 245 21 21 21 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 7 7 7 227 227 227 255 255 255 255 255 255 167 167 167 0 0 0 0 0 0 +0 0 0 64 64 64 255 255 255 255 255 255 241 241 241 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 250 250 250 255 255 255 255 255 255 +55 55 55 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +181 181 181 255 255 255 255 255 255 124 124 124 0 0 0 0 0 0 113 113 113 255 255 255 +255 255 255 255 255 255 255 255 255 245 245 245 37 37 37 0 0 0 0 0 0 219 219 219 +255 255 255 255 255 255 111 111 111 0 0 0 104 104 104 255 255 255 255 255 255 202 202 202 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +24 24 24 255 255 255 255 255 255 255 255 255 51 51 51 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 1 40 48 21 +49 59 26 0 0 0 0 0 0 0 0 0 19 21 13 79 91 55 40 46 28 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 181 181 181 255 255 255 255 255 255 +147 147 147 0 0 0 42 42 42 255 255 255 255 255 255 255 255 255 8 8 8 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 15 15 15 239 239 239 +255 255 255 255 255 255 144 144 144 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 113 113 113 255 255 255 255 255 255 252 252 252 38 38 38 0 0 0 +0 0 0 64 64 64 255 255 255 255 255 255 241 241 241 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 250 250 250 255 255 255 255 255 255 +55 55 55 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +181 181 181 255 255 255 255 255 255 124 124 124 0 0 0 0 0 0 2 2 2 194 194 194 +255 255 255 255 255 255 255 255 255 106 106 106 0 0 0 0 0 0 0 0 0 219 219 219 +255 255 255 255 255 255 111 111 111 0 0 0 104 104 104 255 255 255 255 255 255 202 202 202 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +24 24 24 255 255 255 255 255 255 255 255 255 51 51 51 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 1 2 0 10 13 3 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 19 21 13 115 132 80 200 229 138 208 238 144 206 235 142 54 62 37 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 181 181 181 255 255 255 255 255 255 +147 147 147 0 0 0 42 42 42 255 255 255 255 255 255 255 255 255 8 8 8 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 125 125 125 255 255 255 +255 255 255 250 250 250 30 30 30 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 10 10 10 234 234 234 255 255 255 255 255 255 156 156 156 0 0 0 +0 0 0 64 64 64 255 255 255 255 255 255 241 241 241 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 250 250 250 255 255 255 255 255 255 +55 55 55 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +181 181 181 255 255 255 255 255 255 124 124 124 0 0 0 0 0 0 0 0 0 34 34 34 +242 242 242 255 255 255 190 190 190 1 1 1 0 0 0 0 0 0 0 0 0 219 219 219 +255 255 255 255 255 255 111 111 111 0 0 0 104 104 104 255 255 255 255 255 255 202 202 202 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +24 24 24 255 255 255 255 255 255 255 255 255 51 51 51 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 47 60 15 162 208 51 176 226 55 143 183 44 57 73 18 1 1 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +19 21 13 115 132 80 200 229 138 208 238 144 208 238 144 208 238 144 208 238 144 115 132 80 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 105 105 105 187 187 187 +187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 +187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 235 235 235 255 255 255 255 255 255 +147 147 147 0 0 0 42 42 42 255 255 255 255 255 255 255 255 255 8 8 8 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 11 11 235 235 235 255 255 255 +255 255 255 154 154 154 0 0 0 0 0 0 0 0 0 0 0 0 67 67 67 153 153 153 +153 153 153 153 153 153 153 153 153 217 217 217 255 255 255 255 255 255 249 249 249 30 30 30 +0 0 0 64 64 64 255 255 255 255 255 255 251 251 251 187 187 187 187 187 187 187 187 187 +187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 +187 187 187 187 187 187 143 143 143 0 0 0 0 0 0 250 250 250 255 255 255 255 255 255 +202 202 202 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 +187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 7 7 7 0 0 0 +181 181 181 255 255 255 255 255 255 124 124 124 0 0 0 0 0 0 0 0 0 0 0 0 +61 61 61 116 116 116 23 23 23 0 0 0 0 0 0 0 0 0 0 0 0 219 219 219 +255 255 255 255 255 255 111 111 111 0 0 0 104 104 104 255 255 255 255 255 255 202 202 202 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +24 24 24 255 255 255 255 255 255 255 255 255 51 51 51 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +4 5 3 162 208 51 176 226 55 176 226 55 176 226 55 176 226 55 144 185 45 55 71 17 +1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 9 5 115 132 80 +200 229 138 208 238 144 208 238 144 208 238 144 208 238 144 208 238 144 208 238 144 122 139 84 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 143 143 143 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +147 147 147 0 0 0 42 42 42 255 255 255 255 255 255 255 255 255 8 8 8 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 114 114 114 255 255 255 255 255 255 +252 252 252 37 37 37 0 0 0 0 0 0 0 0 0 0 0 0 112 112 112 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 146 146 146 +0 0 0 64 64 64 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 195 195 195 0 0 0 0 0 0 250 250 250 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 9 9 9 0 0 0 +181 181 181 255 255 255 255 255 255 124 124 124 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 219 219 219 +255 255 255 255 255 255 111 111 111 0 0 0 104 104 104 255 255 255 255 255 255 202 202 202 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +24 24 24 255 255 255 255 255 255 255 255 255 51 51 51 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +24 31 10 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +144 185 45 55 71 17 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 156 178 108 208 238 144 +208 238 144 208 238 144 208 238 144 208 238 144 208 238 144 208 238 144 208 238 144 122 139 84 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 143 143 143 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +115 115 115 0 0 0 42 42 42 255 255 255 255 255 255 255 255 255 8 8 8 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 7 7 7 227 227 227 255 255 255 255 255 255 +164 164 164 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 112 112 112 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 247 247 247 +25 25 25 37 37 37 251 251 251 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 195 195 195 0 0 0 0 0 0 219 219 219 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 9 9 9 0 0 0 +181 181 181 255 255 255 255 255 255 124 124 124 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 219 219 219 +255 255 255 255 255 255 111 111 111 0 0 0 104 104 104 255 255 255 255 255 255 202 202 202 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +24 24 24 255 255 255 255 255 255 255 255 255 51 51 51 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +27 35 8 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 146 187 46 59 75 18 1 1 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 28 32 19 208 238 144 208 238 144 +208 238 144 208 238 144 208 238 144 208 238 144 208 238 144 208 238 144 208 238 144 122 139 84 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 29 29 29 51 51 51 +51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 +51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 45 45 45 +1 1 1 0 0 0 8 8 8 51 51 51 51 51 51 51 51 51 2 2 2 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 16 16 16 68 68 68 68 68 68 68 68 68 +23 23 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 30 30 30 68 68 68 +68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 +24 24 24 0 0 0 30 30 30 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 +51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 +51 51 51 51 51 51 39 39 39 0 0 0 0 0 0 16 16 16 51 51 51 51 51 51 +51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 +51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 2 2 2 0 0 0 +48 48 48 68 68 68 68 68 68 33 33 33 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 88 88 88 +102 102 102 102 102 102 44 44 44 0 0 0 30 30 30 75 75 75 75 75 75 59 59 59 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +7 7 7 75 75 75 75 75 75 75 75 75 13 13 13 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +27 35 8 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 176 226 55 144 185 45 59 75 18 1 1 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 40 46 28 208 238 144 208 238 144 +208 238 144 208 238 144 208 238 144 208 238 144 208 238 144 208 238 144 208 238 144 122 139 84 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +27 35 8 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 144 185 45 59 75 18 +1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 40 46 28 208 238 144 208 238 144 +208 238 144 208 238 144 208 238 144 208 238 144 208 238 144 208 238 144 208 238 144 122 139 84 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +27 35 8 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +144 185 45 59 75 18 1 1 0 0 0 0 0 0 0 40 46 28 208 238 144 208 238 144 +208 238 144 208 238 144 208 238 144 208 238 144 208 238 144 208 238 144 208 238 144 79 91 55 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +27 35 8 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 122 156 38 1 2 0 0 0 0 40 46 28 208 238 144 208 238 144 +208 238 144 208 238 144 208 238 144 208 238 144 208 238 144 208 238 144 141 169 76 3 3 2 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +27 35 8 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 52 67 16 0 0 0 40 46 28 208 238 144 208 238 144 +208 238 144 208 238 144 208 238 144 208 238 144 156 178 108 60 70 37 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +27 35 8 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 81 104 25 0 0 0 17 20 10 206 235 142 208 238 144 +208 238 144 208 238 144 156 178 108 54 62 37 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 75 75 75 +169 169 169 90 90 90 0 0 0 0 0 0 0 0 0 0 0 0 77 77 77 136 136 136 +54 54 54 0 0 0 0 0 0 0 0 0 50 50 50 136 136 136 82 82 82 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 31 31 31 169 169 169 132 132 132 0 0 0 +39 39 39 119 119 119 75 75 75 0 0 0 0 0 0 0 0 0 49 49 49 119 119 119 +65 65 65 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 26 26 26 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 +51 51 51 39 39 39 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 1 1 136 136 136 132 132 132 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 12 12 136 136 136 +120 120 120 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +27 35 8 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 81 104 25 0 0 0 0 0 0 89 95 75 200 229 138 +156 178 108 54 62 37 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 112 112 112 +255 255 255 139 139 139 0 0 0 26 26 26 34 34 34 34 34 34 161 161 161 255 255 255 +122 122 122 34 34 34 34 34 34 34 34 34 116 116 116 255 255 255 168 168 168 34 34 34 +34 34 34 2 2 2 0 0 0 0 0 0 49 49 49 255 255 255 200 200 200 0 0 0 +88 88 88 255 255 255 169 169 169 17 17 17 17 17 17 17 17 17 116 116 116 255 255 255 +149 149 149 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 8 8 8 0 0 0 +0 0 0 130 130 130 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 194 194 194 4 5 3 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 +35 35 35 255 255 255 249 249 249 34 34 34 16 16 16 0 0 0 0 0 0 30 30 30 +34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 54 54 54 255 255 255 +229 229 229 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 +24 24 24 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +27 35 8 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 81 104 25 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 88 88 88 +203 203 203 108 108 108 0 0 0 196 196 196 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 12 12 12 0 0 0 0 0 0 38 38 38 203 203 203 158 158 158 0 0 0 +84 84 84 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 123 123 123 0 0 0 +0 0 0 130 130 130 255 255 255 173 173 173 102 102 102 102 102 102 102 102 102 135 135 135 +255 255 255 194 194 194 29 29 29 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 122 122 122 0 0 0 106 106 106 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +254 254 254 44 44 44 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +27 35 8 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 81 104 25 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 92 92 92 119 119 119 119 119 119 196 196 196 255 255 255 +153 153 153 85 85 85 85 85 85 85 85 85 147 147 147 255 255 255 200 200 200 119 119 119 +119 119 119 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +16 16 16 128 128 128 136 136 136 136 136 136 136 136 136 136 136 136 185 185 185 255 255 255 +202 202 202 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 65 65 65 0 0 0 +0 0 0 130 130 130 255 255 255 118 118 118 0 0 0 0 0 0 0 0 0 55 55 55 +255 255 255 194 194 194 13 13 13 119 119 119 119 119 119 119 119 119 119 119 119 119 119 119 +120 120 120 255 255 255 251 251 251 119 119 119 57 57 57 0 0 0 139 139 139 255 255 255 +157 157 157 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 +85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 209 209 209 +255 255 255 64 64 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +27 35 8 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 81 104 25 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 96 96 96 170 170 170 +167 167 167 42 42 42 0 0 0 0 0 0 0 0 0 0 0 0 146 146 146 255 255 255 +102 102 102 0 0 0 0 0 0 0 0 0 95 95 95 255 255 255 154 154 154 0 0 0 +0 0 0 0 0 0 0 0 0 39 39 39 170 170 170 170 170 170 96 96 96 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 106 106 106 255 255 255 +142 142 142 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 130 130 130 255 255 255 118 118 118 0 0 0 0 0 0 0 0 0 55 55 55 +255 255 255 194 194 194 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 1 1 255 255 255 248 248 248 0 0 0 0 0 0 0 0 0 131 131 131 238 238 238 +102 102 102 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 171 171 171 +238 238 238 59 59 59 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +27 35 8 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 81 104 25 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 143 143 143 255 255 255 +255 255 255 113 113 113 0 0 0 0 0 0 0 0 0 0 0 0 146 146 146 255 255 255 +102 102 102 0 0 0 0 0 0 0 0 0 95 95 95 255 255 255 154 154 154 0 0 0 +0 0 0 0 0 0 0 0 0 57 57 57 255 255 255 255 255 255 199 199 199 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 106 106 106 255 255 255 +142 142 142 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 130 130 130 255 255 255 118 118 118 0 0 0 0 0 0 0 0 0 55 55 55 +255 255 255 194 194 194 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 1 1 255 255 255 248 248 248 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 114 114 114 238 238 238 217 217 217 31 31 31 0 0 0 0 0 0 +0 0 0 0 0 0 67 67 67 234 234 234 229 229 229 55 55 55 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +20 25 6 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 81 104 25 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 135 135 135 +255 255 255 114 114 114 0 0 0 13 13 13 17 17 17 17 17 17 154 154 154 255 255 255 +122 122 122 34 34 34 34 34 34 34 34 34 116 116 116 255 255 255 161 161 161 17 17 17 +17 17 17 1 1 1 0 0 0 0 0 0 49 49 49 255 255 255 199 199 199 0 0 0 +96 96 96 221 221 221 221 221 221 221 221 221 221 221 221 221 221 221 235 235 235 255 255 255 +240 240 240 221 221 221 221 221 221 221 221 221 221 221 221 221 221 221 106 106 106 0 0 0 +0 0 0 130 130 130 255 255 255 128 128 128 17 17 17 17 17 17 17 17 17 17 17 17 +17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 +18 18 18 255 255 255 248 248 248 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 95 95 95 254 254 254 239 239 239 50 50 50 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 92 92 92 253 253 253 240 240 240 52 52 52 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +1 2 0 146 187 46 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 81 104 25 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 135 135 135 +255 255 255 114 114 114 0 0 0 196 196 196 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 12 12 12 0 0 0 0 0 0 49 49 49 255 255 255 199 199 199 0 0 0 +88 88 88 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 239 239 239 255 255 255 +246 246 246 204 204 204 204 204 204 204 204 204 204 204 204 204 204 204 99 99 99 0 0 0 +0 0 0 130 130 130 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 248 248 248 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +81 81 81 251 251 251 240 240 240 54 54 54 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 106 106 106 255 255 255 235 235 235 44 44 44 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 24 31 10 133 170 41 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 81 104 25 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 135 135 135 +255 255 255 114 114 114 0 0 0 105 105 105 136 136 136 136 136 136 239 239 239 255 255 255 +158 158 158 136 136 136 136 136 136 136 136 136 181 181 181 255 255 255 209 209 209 136 136 136 +136 136 136 6 6 6 0 0 0 0 0 0 49 49 49 255 255 255 199 199 199 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 50 50 50 245 245 245 255 255 255 +253 253 253 81 81 81 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 130 130 130 255 255 255 209 209 209 170 170 170 170 170 170 170 170 170 170 170 170 +170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 +170 170 170 255 255 255 248 248 248 0 0 0 0 0 0 0 0 0 27 27 27 157 157 157 +249 249 249 255 255 255 200 200 200 153 153 153 153 153 153 153 153 153 153 153 153 153 153 153 +153 153 153 153 153 153 153 153 153 153 153 153 153 153 153 231 231 231 255 255 255 232 232 232 +133 133 133 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 41 53 13 133 170 41 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 81 104 25 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 135 135 135 +255 255 255 114 114 114 0 0 0 0 0 0 0 0 0 90 90 90 255 255 255 230 230 230 +6 6 6 0 0 0 0 0 0 0 0 0 95 95 95 255 255 255 154 154 154 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 49 49 49 255 255 255 199 199 199 0 0 0 +0 0 0 0 0 0 0 0 0 16 16 16 128 128 128 245 245 245 255 255 255 209 209 209 +255 255 255 252 252 252 146 146 146 26 26 26 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 130 130 130 255 255 255 118 118 118 0 0 0 0 0 0 0 0 0 18 18 18 +85 85 85 65 65 65 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 1 1 255 255 255 248 248 248 0 0 0 0 0 0 0 0 0 45 45 45 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +222 222 222 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 41 53 13 133 170 41 176 226 55 +176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 81 104 25 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 135 135 135 +255 255 255 114 114 114 0 0 0 3 3 2 124 124 124 251 251 251 252 252 252 80 80 80 +0 0 0 0 0 0 0 0 0 0 0 0 95 95 95 255 255 255 154 154 154 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 49 49 49 255 255 255 199 199 199 0 0 0 +0 0 0 19 19 19 131 131 131 240 240 240 255 255 255 252 252 252 139 139 139 2 2 2 +131 131 131 251 251 251 255 255 255 247 247 247 147 147 147 29 29 29 0 0 0 0 0 0 +0 0 0 130 130 130 255 255 255 118 118 118 0 0 0 0 0 0 0 0 0 55 55 55 +255 255 255 194 194 194 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 1 1 255 255 255 248 248 248 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23 23 23 255 255 255 +225 225 225 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 41 53 13 +133 170 41 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 81 104 25 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 135 135 135 +255 255 255 114 114 114 0 0 0 171 171 171 255 255 255 254 254 254 105 105 105 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 95 95 95 255 255 255 154 154 154 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 49 49 49 255 255 255 199 199 199 0 0 0 +38 38 38 242 242 242 255 255 255 255 255 255 181 181 181 54 54 54 0 0 0 0 0 0 +0 0 0 42 42 42 164 164 164 252 252 252 255 255 255 249 249 249 67 67 67 0 0 0 +0 0 0 130 130 130 255 255 255 118 118 118 0 0 0 0 0 0 0 0 0 55 55 55 +255 255 255 194 194 194 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 1 1 255 255 255 248 248 248 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23 23 23 255 255 255 +225 225 225 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 47 60 15 139 178 43 176 226 55 176 226 55 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 81 104 25 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 135 135 135 +255 255 255 114 114 114 0 0 0 88 88 88 240 240 240 85 85 85 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 95 95 95 255 255 255 154 154 154 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 49 49 49 255 255 255 199 199 199 0 0 0 +0 0 0 204 204 204 187 187 187 54 54 54 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 33 33 33 153 153 153 231 231 231 11 11 11 0 0 0 +0 0 0 130 130 130 255 255 255 118 118 118 0 0 0 0 0 0 0 0 0 55 55 55 +255 255 255 194 194 194 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 1 1 255 255 255 248 248 248 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23 23 23 255 255 255 +225 225 225 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 52 66 16 139 178 43 176 226 55 176 226 55 176 226 55 +176 226 55 176 226 55 176 226 55 74 93 30 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 135 135 135 +255 255 255 114 114 114 0 0 0 0 0 0 20 20 20 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 19 19 19 51 51 51 31 31 31 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 49 49 49 255 255 255 199 199 199 0 0 0 +0 0 0 11 11 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 11 11 0 0 0 0 0 0 +0 0 0 130 130 130 255 255 255 118 118 118 0 0 0 0 0 0 0 0 0 55 55 55 +255 255 255 194 194 194 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 1 1 255 255 255 248 248 248 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23 23 23 255 255 255 +225 225 225 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 52 67 16 139 178 43 176 226 55 +176 226 55 176 226 55 162 208 51 20 25 6 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 133 133 133 247 247 247 +255 255 255 246 246 246 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 +238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 +238 238 238 146 146 146 0 0 0 54 54 54 241 241 241 255 255 255 251 251 251 238 238 238 +238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 +238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 238 225 225 225 0 0 0 +0 0 0 130 130 130 255 255 255 236 236 236 221 221 221 221 221 221 221 221 221 227 227 227 +255 255 255 194 194 194 0 0 0 0 0 0 30 30 30 221 221 221 221 221 221 221 221 221 +221 221 221 255 255 255 239 239 239 0 0 0 0 0 0 0 0 0 39 39 39 221 221 221 +221 221 221 221 221 221 221 221 221 221 221 221 221 221 221 221 221 221 224 224 224 255 255 255 +251 251 251 221 221 221 221 221 221 221 221 221 221 221 221 221 221 221 221 221 221 221 221 221 +213 213 213 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 52 67 16 +122 156 38 106 132 44 30 39 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 96 96 96 170 170 170 +170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 +170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 +170 170 170 104 104 104 0 0 0 39 39 39 170 170 170 170 170 170 170 170 170 170 170 170 +170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 +170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 161 161 161 0 0 0 +0 0 0 96 96 96 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 +187 187 187 99 99 99 0 0 0 0 0 0 26 26 26 187 187 187 187 187 187 187 187 187 +187 187 187 183 183 183 92 92 92 0 0 0 0 0 0 0 0 0 33 33 33 187 187 187 +187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 +187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 187 +181 181 181 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 diff --git a/bsp/spacemit/dm/hwcrypto/Kconfig b/bsp/spacemit/dm/hwcrypto/Kconfig new file mode 100644 index 000000000000..77c12e099977 --- /dev/null +++ b/bsp/spacemit/dm/hwcrypto/Kconfig @@ -0,0 +1,17 @@ +config RT_HWCRYPTO_SPACEMIT + bool "Spacemit Crypto Engine" + depends on RT_USING_CLK + depends on RT_USING_RESET + depends on RT_USING_HWCRYPTO + depends on RT_HWCRYPTO_USING_AES + depends on RT_HWCRYPTO_USING_AES_ECB + depends on RT_HWCRYPTO_USING_AES_CBC + default y + +config RT_HWCRYPTO_RNG_SPACEMIT + bool "Spacemit RNG Engine" + depends on RT_USING_CLK + depends on RT_USING_RESET + depends on RT_USING_HWCRYPTO + depends on RT_HWCRYPTO_USING_RNG + default y diff --git a/bsp/spacemit/dm/hwcrypto/SConscript b/bsp/spacemit/dm/hwcrypto/SConscript new file mode 100644 index 000000000000..d6348b177209 --- /dev/null +++ b/bsp/spacemit/dm/hwcrypto/SConscript @@ -0,0 +1,15 @@ +from building import * + +cwd = GetCurrentDir() +src = [] +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_HWCRYPTO_SPACEMIT']): + src += ['hw-crypto-spacemit.c'] + +if GetDepend(['RT_HWCRYPTO_RNG_SPACEMIT']): + src += ['hw-rng-spacemit.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/hwcrypto/hw-crypto-spacemit.c b/bsp/spacemit/dm/hwcrypto/hw-crypto-spacemit.c new file mode 100644 index 000000000000..fc484dc4b0b2 --- /dev/null +++ b/bsp/spacemit/dm/hwcrypto/hw-crypto-spacemit.c @@ -0,0 +1,1189 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include + +#include "spacemit.h" + +#define SPACEMIT_AES_BUFFER_LEN (1024 * 256) + +#define WORK_BUF_SIZE 2048 +#define CTR_COUNTER_LITTLE_ENDIAN 0x0000 +#define CTR_COUNTER_BIG_ENDIAN 0x1000 +#define BYTES_TO_BITS 8 +#define SPACEMIT_SECENG_SIZE 0x3000 + +#define ENGINE_DMA_ADDR_HIGH_OFFSET 0x14c +#define SW_RESETN RT_BIT(0) +#define MASTER_CLK_EN RT_BIT(1) +#define SLAVE_CLK_EN RT_BIT(2) +#define WADDR_BIT32 RT_BIT(4) +#define RADDR_BIT32 RT_BIT(5) + +#define CE_BIU_REG_OFFSET 0x00000000L +#define CE_ADEC_REG_OFFSET 0x00000400L +#define CE_DMA_REG_OFFSET 0x00000800L +#define CE_ABUS_REG_OFFSET 0x00000c00L +#define CE_CRYPTO_REG_OFFSET 0x00001000L +#define CE_HASH_REG_OFFSET 0x00001800L + +#define CE_ADEC_CTRL 0x0000 +#define CE_ADEC_CTRL2 0x0004 +#define CE_AXI_SL_CTRL 0x0008 +#define CE_ADEC_INT 0x000c +#define CE_ADEC_INT_MSK 0x0010 +#define CE_ADEC_ACC_ERR_ADR 0x0014 +#define CE_ADEC_MP_FIFO_ERR_ADR 0x0018 + +#define CE_ABUS_BUS_CTRL 0x0000 + +#define SP_HST_INTERRUPT_MASK 0x0cc +#define SP_INTERRUPT_RST 0x218 +#define SP_INTERRUPT_MASK 0x21c +#define SP_CONTROL 0x220 + +#define CE_HASH_CONFIG_REG 0x0000 +#define CE_HASH_CONTROL_REG 0x0004 +#define CE_HASH_COMMAND_REG 0x0008 +#define CE_HASH_STATUS_REG 0x000c +#define CE_HASH_INCOME_SEG_SZ_REG 0x0010 +#define CE_HASH_TOTAL_MSG_SZ_L_REG 0x0018 +#define CE_HASH_TOTAL_MSG_SZ_H_REG 0x001c +#define CE_HASH_DIGEST_BASE 0x0020 +#define CE_HASH_DIGEST_REG(a) (CE_HASH_DIGEST_BASE + (a << 2)) +#define CE_HASH_DIGEST_H_BASE 0x0040 +#define CE_HASH_DIGEST_H_REG(a) (CE_HASH_DIGEST_H_BASE + (a << 2)) +#define CE_HASH_CONTEXTO_BASE 0x0064 +#define CE_HASH_CONTEXTO_REG(a) (CE_HASH_CONTEXTO_BASE + (a << 2)) +#define CE_HASH_CONTEXTO_H_BASE 0x0080 +#define CE_HASH_CONTEXTO_H_REG(a) (CE_HASH_CONTEXTO_H_BASE + (a << 2)) +#define CE_HASH_KEY_BASE 0x00a4 +#define CE_HASH_KEY_REG(a) (CE_HASH_KEY_BASE + (a << 2)) + +#define CE_DMA_IN_CTRL 0x0000 +#define CE_DMA_IN_STATUS 0x0004 +#define CE_DMA_IN_SRC_ADR 0x0008 +#define CE_DMA_IN_XFER_CNTR 0x000c +#define CE_DMA_IN_NX_LL_ADR 0x0010 +#define CE_DMA_IN_INT 0x0014 +#define CE_DMA_IN_INT_MASK 0x0018 +#define CE_DMA_OUT_CTRL 0x001c +#define CE_DMA_OUT_STATUS 0x0020 +#define CE_DMA_OUT_DEST_ADR 0x0024 +#define CE_DMA_OUT_XFER_CNTR 0x0028 +#define CE_DMA_OUT_NX_LL_ADR 0x002c +#define CE_DMA_OUT_INT 0x0030 +#define CE_DMA_OUT_INT_MASK 0x0034 +#define CE_DMA_AXI_CTRL 0x0038 +#define CE_DMA_IF_RCOUNT 0x003c +#define CE_DMA_IF_RD_PTR_ERR 0x0040 +#define CE_DMA_OF_SPACE 0x0044 +#define CE_DMA_OF_RD_PTR_ERR 0x0048 +#define CE_DMA_IF_RAM_BASE 0x0100 +#define CE_DMA_IF_RAM_REG(a) (CE_DMA_IF_RAM_BASE + a*0x4) +#define CE_DMA_OF_RAM_BASE 0x0300 +#define CE_DMA_OF_RAM_REG(a) (CE_DMA_OF_RAM_BASE + a*0x4) + +#define CE_BIU_HST_INTERRUPT_MASK 0x00cc +#define CE_BIU_SP_INTERRUPT_MASK 0x021c +#define CE_BIU_SP_CONTROL 0x0220 + +#define CE_CRYPTO_AES_CONFIG_REG 0x0000 +#define CE_CRYPTO_AES_CONTROL_REG 0x0004 +#define CE_CRYPTO_AES_COMMAND_REG 0x0008 +#define CE_CRYPTO_AES_STATUS_REG 0x000c +#define CE_CRYPTO_AES_INTRPT_SRC_REG 0x0010 +#define CE_CRYPTO_AES_INTRPT_SRC_EN_REG 0x0014 +#define CE_CRYPTO_AES_STREAM_SIZE_REG 0x0018 +#define CE_CRYPTO_ENGINE_SEL_REG 0x00a8 + +#define CE_CRYPTO_K2_BASE 0x0058 +#define CE_CRYPTO_K2_W_REG(a) (CE_CRYPTO_K2_BASE + a * 0x4) +#define CE_CRYPTO_K1_BASE 0x0078 +#define CE_CRYPTO_K1_W_REG(a) (CE_CRYPTO_K1_BASE + a*0x4) +#define CE_CRYPTO_IV_BASE 0x0098 +#define CE_CRYPTO_IV_REG(a) (CE_CRYPTO_IV_BASE + a*0x4) + +#define AES_INTERRUPT_FLAG RT_BIT(0) +#define AES_ERR1_INTERRUPT_FLAG RT_BIT(1) +#define AES_ERR2_INTERRUPT_FLAG RT_BIT(2) +#define AES_INTERRUPT_MASK (AES_INTERRUPT_FLAG | AES_ERR1_INTERRUPT_FLAG | \ + AES_ERR2_INTERRUPT_FLAG) + +#define BIT_DMA_INOUT_DONE RT_BIT(0) +#define BIT_DMA_INOUT_BUS_ERR RT_BIT(1) +#define BIT_DMA_INOUT_LL_ERR RT_BIT(2) +#define BIT_DMA_INOUT_PAR_ERR RT_BIT(3) +#define BIT_DMA_INOUT_PAUSE_CMPL_ERR RT_BIT(4) +#define BIT_DMA_INOUT_DATA_PAR_ERR RT_BIT(5) +#define DMA_INTERRUPT_MASK (BIT_DMA_INOUT_DONE | BIT_DMA_INOUT_BUS_ERR | \ + BIT_DMA_INOUT_LL_ERR | BIT_DMA_INOUT_PAR_ERR | \ + BIT_DMA_INOUT_PAUSE_CMPL_ERR | BIT_DMA_INOUT_DATA_PAR_ERR) + +#define BIU_MASK RT_BIT(0) +#define ADEC_MASK (RT_BIT(1) | RT_BIT(5)) + +#define AES_BLOCK_SIZE 16 + +#define ENGINE_MAX 2 + +enum adec_acc_eng +{ + /* Reset bit */ + E_ACC_ENG_DMA = 1, + E_ACC_ENG_HASH = 5, + E_ACC_ENG_CRYPTO = 3, + E_ACC_ENG_ALL, +}; + +enum abus_grp_a +{ + E_ABUS_GRP_A_HASH = 0x0, +}; + +enum abus_grp_b +{ + E_ABUS_GRP_B_AES = 0x0, + E_ABUS_GRP_B_BYPASS = 0x2, +}; + +enum abus_cross_bar +{ + E_ABUS_STRAIGHT = 0, + E_ABUS_CROSS, +}; + +enum crypto_eng_sel +{ + E_ENG_AES = 0, +}; + +enum crypto_aes_status +{ + AES_INVALID, + AES_DONE, + AES_ERROR +}; + +enum crypto_dma_status +{ + DMA_INVALID, + DMA_INOUT_DONE, + DMA_INOUT_ERROR +}; + +struct spacemit_crypto; + +struct spacemit_crypto_engine +{ + struct rt_hwcrypto_device parent; + + struct spacemit_crypto *crypto; + + int irq; + void *base; + + void *in_buffer, *out_buffer; + rt_ubase_t in_buffer_dma, out_buffer_dma; + + enum crypto_aes_status aes_status; + enum crypto_dma_status dma_in_status; + enum crypto_dma_status dma_out_status; + + struct rt_completion aes_done; + struct rt_completion dma_output_done; + struct rt_completion dma_input_done; + + struct rt_mutex lock; + + rt_uint8_t internal_working_buffer[WORK_BUF_SIZE * 2] rt_align(32); +}; + +struct spacemit_crypto +{ + struct rt_clk *clk; + struct rt_reset_control *rstc; + struct rt_syscon *ciu_regmap; + + rt_uint32_t engine_nr; + struct spacemit_crypto_engine engine[ENGINE_MAX]; +}; + +#define raw_to_spacemit_crypto_engine(raw) rt_container_of((raw)->parent.device, struct spacemit_crypto_engine, parent) + +static void dma_write32(struct spacemit_crypto_engine *ce, int offset, rt_uint32_t value) +{ + tcm_override_writel(ce->base + CE_DMA_REG_OFFSET + offset, value); +} + +static rt_uint32_t dma_read32(struct spacemit_crypto_engine *ce, int offset) +{ + return tcm_override_readl(ce->base + CE_DMA_REG_OFFSET + offset); +} + +static void biu_write32(struct spacemit_crypto_engine *ce, int offset, rt_uint32_t value) +{ + tcm_override_writel(ce->base + CE_BIU_REG_OFFSET + offset, value); +} + +static rt_uint32_t biu_read32(struct spacemit_crypto_engine *ce, int offset) +{ + return tcm_override_readl(ce->base + CE_BIU_REG_OFFSET + offset); +} + +static void adec_write32(struct spacemit_crypto_engine *ce, int offset, rt_uint32_t value) +{ + tcm_override_writel(ce->base + CE_ADEC_REG_OFFSET + offset, value); +} + +static rt_uint32_t adec_read32(struct spacemit_crypto_engine *ce, int offset) +{ + return tcm_override_readl(ce->base + CE_ADEC_REG_OFFSET + offset); +} + +static void abus_write32(struct spacemit_crypto_engine *ce, int offset, rt_uint32_t value) +{ + tcm_override_writel(ce->base + CE_ABUS_REG_OFFSET + offset, value); +} + +static rt_uint32_t abus_read32(struct spacemit_crypto_engine *ce, int offset) +{ + return tcm_override_readl(ce->base + CE_ABUS_REG_OFFSET + offset); +} + +static void crypto_write32(struct spacemit_crypto_engine *ce, int offset, rt_uint32_t value) +{ + tcm_override_writel(ce->base + CE_CRYPTO_REG_OFFSET + offset, value); +} + +static rt_uint32_t crypto_read32(struct spacemit_crypto_engine *ce, int offset) +{ + return tcm_override_readl(ce->base + CE_CRYPTO_REG_OFFSET + offset); +} + +static void dma_output_config(struct spacemit_crypto_engine *ce, int wid_ext, int wid) +{ + rt_uint32_t val; + + val = dma_read32(ce, CE_DMA_OUT_CTRL); + val &= 0x0f0f0000; + val |= (0x7 << 28) | /* Dis error check */ + ((wid_ext & 0xf) << 20) | /* Rid ext */ + (0x1 << 18) | /* Dis out-of-order */ + (0x1 << 17) | /* Data 64 Byte aligned */ + (0x1 << 15) | /* FIFO bus size 64bit */ + (0x1 << 13) | /* Burst type: Inc */ + (0x8 << 8) | /* Burst len */ + ((wid & 0xf) << 4); + + dma_write32(ce, CE_DMA_OUT_CTRL, val); +} + +static void dma_output_address(struct spacemit_crypto_engine *ce, + rt_uint32_t dst_addr, rt_uint32_t dst_size, rt_bool_t chained) +{ + if (chained) + { + dma_write32(ce, CE_DMA_OUT_NX_LL_ADR, dst_addr); + dma_write32(ce, CE_DMA_OUT_DEST_ADR, 0x0); + dma_write32(ce, CE_DMA_OUT_XFER_CNTR, 0x0); + } + else + { + dma_write32(ce, CE_DMA_OUT_NX_LL_ADR, 0x0); + dma_write32(ce, CE_DMA_OUT_DEST_ADR, dst_addr); + dma_write32(ce, CE_DMA_OUT_XFER_CNTR, dst_size); + } +} + +static void dma_output_start(struct spacemit_crypto_engine *ce) +{ + rt_uint32_t val; + + val = dma_read32(ce, CE_DMA_OUT_INT); + dma_write32(ce, CE_DMA_OUT_INT, val); + + val = dma_read32(ce, CE_DMA_OUT_CTRL); + val |= 0x1; + dma_write32(ce, CE_DMA_OUT_CTRL, val); +} + +static void dma_output_stop(struct spacemit_crypto_engine *ce) +{ + rt_uint32_t val; + + val = dma_read32(ce, CE_DMA_OUT_CTRL); + val &= ~0x1; + dma_write32(ce, CE_DMA_OUT_CTRL, val); +} + +static void dma_input_config(struct spacemit_crypto_engine *ce, int rid_ext, int rid) +{ + rt_uint32_t val; + + val = dma_read32(ce, CE_DMA_IN_CTRL); + val &= 0x0f0f0000; + val |= (0x7 << 28) | /* Dis error check */ + ((rid_ext & 0xf) << 20) | /* Rid ext */ + (0x1 << 18) | /* Dis out-of-order */ + (0x1 << 17) | /* Data 64 Byte aligned */ + (0x1 << 15) | /* FIFO bus size 64bit */ + (0x1 << 13) | /* Burst type: Inc */ + (0x8 << 8) | /* Burst len */ + ((rid & 0xf) << 4); + + dma_write32(ce, CE_DMA_IN_CTRL, val); +} + +static void dma_input_address(struct spacemit_crypto_engine *ce, + rt_uint32_t src_addr, rt_uint32_t src_size, rt_bool_t chained) +{ + if (chained) + { + dma_write32(ce, CE_DMA_IN_NX_LL_ADR, src_addr); + dma_write32(ce, CE_DMA_IN_SRC_ADR, 0x0); + dma_write32(ce, CE_DMA_IN_XFER_CNTR, 0x0); + } + else + { + dma_write32(ce, CE_DMA_IN_NX_LL_ADR, 0x0); + dma_write32(ce, CE_DMA_IN_SRC_ADR, src_addr); + dma_write32(ce, CE_DMA_IN_XFER_CNTR, src_size); + } +} + +static void dma_input_start(struct spacemit_crypto_engine *ce) +{ + rt_uint32_t val; + + val = dma_read32(ce, CE_DMA_IN_INT); + dma_write32(ce, CE_DMA_IN_INT, val); + + val = dma_read32(ce, CE_DMA_IN_CTRL); + val |= 0x1; + dma_write32(ce, CE_DMA_IN_CTRL, val); +} + +static void dma_input_stop(struct spacemit_crypto_engine *ce) +{ + rt_uint32_t val; + + val = dma_read32(ce, CE_DMA_IN_CTRL); + val &= ~0x1; + dma_write32(ce, CE_DMA_IN_CTRL, val); +} + +static rt_err_t dma_wait_int_input_finish(struct spacemit_crypto_engine *ce) +{ + rt_completion_wait(&ce->dma_input_done, RT_WAITING_FOREVER); + + if (ce->dma_in_status != DMA_INOUT_DONE) + { + return -RT_EINVAL; + } + + return RT_EOK; +} + +static rt_err_t dma_wait_int_output_finish(struct spacemit_crypto_engine *ce) +{ + rt_completion_wait(&ce->dma_output_done, RT_WAITING_FOREVER); + + if (ce->dma_out_status != DMA_INOUT_DONE) + { + return -RT_EINVAL; + } + + return RT_EOK; +} + +static void adec_biu_clear_int_flag(struct spacemit_crypto_engine *ce) +{ + volatile rt_uint32_t val; + + val = adec_read32(ce, CE_ADEC_INT); + adec_write32(ce, CE_ADEC_INT, val); + + val = biu_read32(ce, SP_INTERRUPT_RST); + biu_write32(ce, SP_INTERRUPT_RST, val); +} + +static rt_err_t adec_engine_hw_reset(struct spacemit_crypto_engine *ce, enum adec_acc_eng engine) +{ + rt_uint32_t val, tmp; + + if (engine == E_ACC_ENG_ALL) + { + tmp = 0xffff; + } + else + { + tmp = 1 << engine; + } + + val = adec_read32(ce, CE_ADEC_CTRL); + val |= tmp; + adec_write32(ce, CE_ADEC_CTRL, val); + val &= ~tmp; + adec_write32(ce, CE_ADEC_CTRL, val); + + if (engine == E_ACC_ENG_DMA) + { + rt_syscon_update_bits(ce->crypto->ciu_regmap, + ENGINE_DMA_ADDR_HIGH_OFFSET, WADDR_BIT32 | RADDR_BIT32, 0); + } + + return RT_EOK; +} + +static rt_err_t abus_set_mode(struct spacemit_crypto_engine *ce, + enum abus_grp_a grp_a_mode, enum abus_grp_b grp_b_mode, + enum abus_cross_bar input_bar, enum abus_cross_bar output_bar) +{ + uint32_t val; + + val = abus_read32(ce, CE_ABUS_BUS_CTRL); + + val &= ~(0x77 << 0x4); + val |= (grp_a_mode << 0x4) | (grp_b_mode << 0x8); + + if (input_bar == E_ABUS_STRAIGHT) + { + val &= ~(0x1 << 0x0); + } + else if (input_bar == E_ABUS_CROSS) + { + val |= 0x1 << 0x0; + } + else + { + return -RT_EINVAL; + } + + if (output_bar == E_ABUS_STRAIGHT) + { + val &= ~(0x1 << 0x2); + } + else if (output_bar == E_ABUS_CROSS) + { + val |= 0x1 << 0x2; + } + else + { + return -RT_EINVAL; + } + + abus_write32(ce, CE_ABUS_BUS_CTRL, val); + + return RT_EOK; +} + +static void enable_biu_mask(struct spacemit_crypto_engine *ce) +{ + rt_uint32_t val; + val = biu_read32(ce, SP_INTERRUPT_MASK); + val &=~BIU_MASK; + biu_write32(ce, SP_INTERRUPT_MASK, val); +} + +static void enable_adec_mask(struct spacemit_crypto_engine *ce) +{ + rt_uint32_t val; + val = adec_read32(ce, CE_ADEC_INT_MSK); + val &=~ADEC_MASK; + adec_write32(ce, CE_ADEC_INT_MSK, val); +} + +static void enable_engine_irq(struct spacemit_crypto_engine *ce) +{ + rt_uint32_t val; + + /* Clear aes INT */ + val = crypto_read32(ce, CE_CRYPTO_AES_INTRPT_SRC_REG); + crypto_write32(ce, CE_CRYPTO_AES_INTRPT_SRC_REG, val); + + val = crypto_read32(ce, CE_CRYPTO_AES_INTRPT_SRC_EN_REG); + val |= AES_INTERRUPT_MASK; + crypto_write32(ce, CE_CRYPTO_AES_INTRPT_SRC_EN_REG, val); + + val = dma_read32(ce, CE_DMA_OUT_INT_MASK); + val &= ~DMA_INTERRUPT_MASK; + dma_write32(ce, CE_DMA_OUT_INT_MASK, val); + + val = dma_read32(ce, CE_DMA_IN_INT_MASK); + val &= ~DMA_INTERRUPT_MASK; + dma_write32(ce, CE_DMA_IN_INT_MASK, val); +} + +static rt_err_t select_engine_crypto(struct spacemit_crypto_engine *ce, + enum crypto_eng_sel engine) +{ + rt_uint32_t val; + + val = crypto_read32(ce, CE_CRYPTO_ENGINE_SEL_REG); + val &= ~0x3; + + switch (engine) + { + case E_ENG_AES: val |= 0x1; break; + default: + return -RT_EINVAL; + } + + crypto_write32(ce, CE_CRYPTO_ENGINE_SEL_REG, val); + + return RT_EOK; +} + +static void crypto_aes_sw_reset(struct spacemit_crypto_engine *ce) +{ + crypto_write32(ce, CE_CRYPTO_AES_CONTROL_REG, 0x1); + crypto_write32(ce, CE_CRYPTO_AES_CONTROL_REG, 0x0); +} + +static void crypto_aes_start(struct spacemit_crypto_engine *ce) +{ + crypto_write32(ce, CE_CRYPTO_AES_COMMAND_REG, 0x1); +} + +static rt_err_t crypto_aes_wait(struct spacemit_crypto_engine *ce) +{ + rt_completion_wait(&ce->aes_done, RT_WAITING_FOREVER); + + if (ce->aes_status != AES_DONE) + { + return -RT_EINVAL; + } + + return RT_EOK; +} + +static rt_err_t crypto_aes_set_mode(struct spacemit_crypto_engine *ce, + struct hwcrypto_symmetric *symmetric_ctx, + struct hwcrypto_symmetric_info *symmetric_info, + rt_bool_t use_rkey) +{ + rt_uint32_t val; + + select_engine_crypto(ce, E_ENG_AES); + + val = crypto_read32(ce, CE_CRYPTO_AES_CONFIG_REG); + val &= ~(0x7 << 0x3); + + switch (symmetric_ctx->parent.type) + { + case HWCRYPTO_TYPE_AES_ECB: val |= 0x0 << 0x3; break; + case HWCRYPTO_TYPE_AES_CBC: val |= 0x1 << 0x3; break; + default: + break; + } + + val &= ~(0x3 << 0x1); + + switch (symmetric_ctx->key_bitlen) + { + case 128: val |= 0x0 << 0x1; break; + case 192: val |= 0x2 << 0x1; break; + case 256: val |= 0x1 << 0x1; break; + default: + return -RT_EINVAL; + } + + val &= ~(0x1 << 0x0); + + if (symmetric_info->mode == HWCRYPTO_MODE_DECRYPT) + { + val |= 0x1 << 0x0; + } + else + { + val |= 0x0 << 0x0; + } + + val &= ~(0x1 << 0x6); + + if (!use_rkey) + { + val |= 0x0 << 0x6; + } + else + { + val |= 0x1 << 0x6; + } + + crypto_write32(ce, CE_CRYPTO_AES_CONFIG_REG, val); + + return RT_EOK; +} + +static rt_err_t crypto_aes_set_key1(struct spacemit_crypto_engine *ce, + const rt_uint8_t *key, rt_uint16_t keylen) +{ + rt_uint32_t val, key_end; + + if (!key) + { + return RT_EOK; + } + + switch (keylen) + { + case 128: key_end = 4; break; + case 192: key_end = 6; break; + case 256: key_end = 8; break; + default: + return -RT_EINVAL; + } + + for (int reg_index = 0; reg_index < 8; ++reg_index) + { + if (reg_index < key_end) + { + val = ((key[0 + (reg_index << 2)] & 0xff) << 0) | + ((key[1 + (reg_index << 2)] & 0xff) << 8) | + ((key[2 + (reg_index << 2)] & 0xff) << 16) | + ((key[3 + (reg_index << 2)] & 0xff) << 24); + } + else + { + val = 0; + } + + crypto_write32(ce, CE_CRYPTO_K1_W_REG(reg_index), val); + } + + return RT_EOK; +} + + +static void crypto_aes_set_iv(struct spacemit_crypto_engine *ce, const rt_uint8_t *iv) +{ + rt_uint32_t val; + + for (int reg_index = 0; reg_index < 4; ++reg_index) + { + val = ((iv[(reg_index << 2) + 0] & 0xff) << 0) | + ((iv[(reg_index << 2) + 1] & 0xff) << 8) | + ((iv[(reg_index << 2) + 2] & 0xff) << 16) | + ((iv[(reg_index << 2) + 3] & 0xff) << 24); + + crypto_write32(ce, CE_CRYPTO_IV_REG(reg_index), val); + } +} + +static rt_err_t aes_process(struct spacemit_crypto_engine *ce, + struct hwcrypto_symmetric *symmetric_ctx, + struct hwcrypto_symmetric_info *symmetric_info, + rt_uint8_t *buf_in, rt_uint8_t *buf_out, rt_size_t blocks) +{ + rt_err_t err; + rt_uint32_t val; + rt_ubase_t dma_addr_in_low, dma_addr_in_high; + rt_ubase_t dma_addr_out_low, dma_addr_out_high; + struct spacemit_crypto *crypto = ce->crypto; + + rt_memcpy(ce->in_buffer, buf_in, blocks << 4); + + dma_addr_in_high = rt_upper_32_bits(ce->in_buffer_dma); + dma_addr_in_low = rt_lower_32_bits(ce->in_buffer_dma); + dma_addr_out_high = rt_upper_32_bits(ce->out_buffer_dma); + dma_addr_out_low = rt_lower_32_bits(ce->out_buffer_dma); + + /* Reset the HW before using it */ + adec_engine_hw_reset(ce, E_ACC_ENG_DMA); + adec_engine_hw_reset(ce, E_ACC_ENG_CRYPTO); + abus_set_mode(ce, E_ABUS_GRP_A_HASH, E_ABUS_GRP_B_AES, E_ABUS_STRAIGHT, E_ABUS_STRAIGHT); + crypto_aes_sw_reset(ce); + + rt_syscon_read(crypto->ciu_regmap, ENGINE_DMA_ADDR_HIGH_OFFSET, &val); + switch (ce - ce->crypto->engine) + { + case 0: + val &= ~(WADDR_BIT32 | RADDR_BIT32); + val |= ((dma_addr_out_high & 0x1) << 4 | (dma_addr_in_high & 0x1) << 5); + break; + + case 1: + val &= ~0xff00; + val |= ((dma_addr_out_high & 0xf) << 8 | (dma_addr_in_high & 0xf) << 12);; + break; + + default: + return -RT_EINVAL; + } + rt_syscon_write(crypto->ciu_regmap, ENGINE_DMA_ADDR_HIGH_OFFSET, val); + + if (ce->in_buffer_dma & 0x3 || ce->out_buffer_dma & 0x3) + { + return -RT_EINVAL; + } + + enable_biu_mask(ce); + enable_adec_mask(ce); + enable_engine_irq(ce); + + dma_input_config(ce, 0, 0); + dma_output_config(ce, 0, 1); + + dma_input_address(ce, dma_addr_in_low, blocks << 2, RT_FALSE); + dma_output_address(ce, dma_addr_out_low, blocks << 2, RT_FALSE); + + /* Process KEY */ + if ((err = crypto_aes_set_mode(ce, symmetric_ctx, symmetric_info, RT_FALSE))) + { + return err; + } + + if ((err = crypto_aes_set_key1(ce, symmetric_ctx->key, symmetric_ctx->key_bitlen))) + { + return err; + } + + /* Process IV */ + switch (symmetric_ctx->parent.type) + { + case HWCRYPTO_TYPE_AES_CBC: + crypto_aes_set_iv(ce, symmetric_ctx->iv); + break; + + default: + break; + } + + crypto_write32(ce, CE_CRYPTO_AES_STREAM_SIZE_REG, blocks << 4); + + dma_input_start(ce); + dma_output_start(ce); + crypto_aes_start(ce); + + if ((err = dma_wait_int_input_finish(ce))) + { + return err; + } + + if ((err = crypto_aes_wait(ce))) + { + return err; + } + + if ((err = dma_wait_int_output_finish(ce))) + { + return err; + } + + /* Readback IV after operation */ + switch (symmetric_ctx->parent.type) + { + case HWCRYPTO_TYPE_AES_CBC: + crypto_aes_set_iv(ce, symmetric_ctx->iv); + break; + + default: + break; + } + + rt_memcpy(buf_out, ce->out_buffer, blocks << 4); + + return RT_EOK; +} + +static rt_err_t spacemit_crypto_symmetric_crypt( + struct hwcrypto_symmetric *symmetric_ctx, + struct hwcrypto_symmetric_info *symmetric_info) +{ + rt_err_t err; + rt_uint32_t blocks; + rt_uint8_t *buf_in, *buf_out; + struct spacemit_crypto_engine *ce = raw_to_spacemit_crypto_engine(symmetric_ctx); + + if (!symmetric_ctx->iv_len) + { + symmetric_ctx->iv_len = sizeof(symmetric_ctx->iv); + rt_memset(symmetric_ctx->iv, 0, symmetric_ctx->iv_len); + } + + switch (symmetric_ctx->parent.type) + { + case HWCRYPTO_TYPE_AES_ECB: + case HWCRYPTO_TYPE_AES_CBC: + break; + default: + return -RT_ENOSYS; + } + + if (symmetric_info->mode != HWCRYPTO_MODE_ENCRYPT && + symmetric_info->mode != HWCRYPTO_MODE_DECRYPT) + { + return -RT_ENOSYS; + } + + buf_in = (void *)symmetric_info->in; + buf_out = symmetric_info->out; + blocks = symmetric_info->length / AES_BLOCK_SIZE; + + rt_mutex_take(&ce->lock, RT_WAITING_FOREVER); + + if ((rt_ubase_t)buf_in & 0x3 || (rt_ubase_t)buf_out & 0x3) + { + int len_bytes = 0, step_bytes = 0; + rt_uint8_t *in_cpy, *out_cpy, *in_work, *out_work; + rt_uint8_t *aligned_buf_1 = &ce->internal_working_buffer[0]; + rt_uint8_t *aligned_buf_2 = &ce->internal_working_buffer[WORK_BUF_SIZE]; + + len_bytes = blocks << 4; + in_cpy = (rt_uint8_t *)buf_in; + out_cpy = (rt_uint8_t *)buf_out; + + while (len_bytes) + { + step_bytes = len_bytes > WORK_BUF_SIZE ? WORK_BUF_SIZE : len_bytes; + + if ((rt_ubase_t)buf_in & 0x3) + { + rt_memcpy(aligned_buf_1, in_cpy, step_bytes); + in_work = aligned_buf_1; + } + else + { + in_work = in_cpy; + } + + len_bytes -= step_bytes; + in_cpy += step_bytes; + + if ((rt_ubase_t)buf_out & 0x3) + { + rt_memset(aligned_buf_2, 0x0, WORK_BUF_SIZE); + out_work = aligned_buf_2; + } + else + { + out_work = out_cpy; + } + + if ((err = aes_process(ce, symmetric_ctx, symmetric_info, in_work, out_work, step_bytes >> 4))) + { + goto _out_lock; + } + + if ((rt_ubase_t)buf_out & 0x3) + { + rt_memcpy(out_cpy, aligned_buf_2, step_bytes); + } + + out_cpy += step_bytes; + } + } + else + { + err = aes_process(ce, symmetric_ctx, symmetric_info, buf_in, buf_out, blocks); + } + +_out_lock: + rt_mutex_release(&ce->lock); + + return err; +} + +static const struct hwcrypto_symmetric_ops spacemit_crypto_symmetric_ops = +{ + .crypt = spacemit_crypto_symmetric_crypt, +}; + +static rt_err_t spacemit_crypto_create(struct rt_hwcrypto_ctx *ctx) +{ + struct hwcrypto_symmetric *crypto_symmetric; + + if ((ctx->type & HWCRYPTO_MAIN_TYPE_MASK) != HWCRYPTO_TYPE_AES) + { + return -RT_ENOSYS; + } + + crypto_symmetric = rt_container_of(ctx, struct hwcrypto_symmetric, parent); + + crypto_symmetric->ops = &spacemit_crypto_symmetric_ops; + + return RT_EOK; +} + +static void spacemit_crypto_destroy(struct rt_hwcrypto_ctx *ctx) +{ + if (!ctx->contex) + { + return; + } + + if ((ctx->type & HWCRYPTO_MAIN_TYPE_MASK) == HWCRYPTO_TYPE_AES) + { + rt_free(ctx->contex); + } +} + +static rt_err_t spacemit_crypto_copy(struct rt_hwcrypto_ctx *des, + const struct rt_hwcrypto_ctx *src) +{ + if ((src->type & HWCRYPTO_MAIN_TYPE_MASK) != HWCRYPTO_TYPE_AES) + { + return -RT_ENOSYS; + } + + return RT_EOK; +} + +static void spacemit_crypto_reset(struct rt_hwcrypto_ctx *ctx) +{ +} + +static const struct rt_hwcrypto_ops spacemit_crypto_ops = +{ + .create = spacemit_crypto_create, + .destroy = spacemit_crypto_destroy, + .copy = spacemit_crypto_copy, + .reset = spacemit_crypto_reset, +}; + +static void spacemit_crypto_isr(int irq, void *param) +{ + volatile rt_uint32_t val_aes; + struct spacemit_crypto_engine *ce = param; + + /* AES */ + val_aes = crypto_read32(ce, CE_CRYPTO_AES_INTRPT_SRC_REG); + + if (val_aes & AES_INTERRUPT_MASK) + { + crypto_write32(ce, CE_CRYPTO_AES_INTRPT_SRC_REG, val_aes); + adec_biu_clear_int_flag(ce); + + ce->aes_status = (val_aes & AES_INTERRUPT_FLAG) ? AES_DONE : AES_ERROR; + rt_completion_done(&ce->aes_done); + + return; + } + + /* DMA output */ + val_aes = dma_read32(ce, CE_DMA_OUT_INT); + + if (val_aes & DMA_INTERRUPT_MASK) + { + dma_output_stop(ce); + dma_write32(ce, CE_DMA_OUT_INT, val_aes); + adec_biu_clear_int_flag(ce); + + ce->dma_out_status = (val_aes & BIT_DMA_INOUT_DONE) ? DMA_INOUT_DONE : DMA_INOUT_ERROR; + rt_completion_done(&ce->dma_output_done); + + return; + } + + /* DMA input */ + val_aes = dma_read32(ce, CE_DMA_IN_INT); + + if (val_aes & DMA_INTERRUPT_MASK) + { + dma_input_stop(ce); + dma_write32(ce, CE_DMA_IN_INT, val_aes); + adec_biu_clear_int_flag(ce); + + ce->dma_in_status = (val_aes & BIT_DMA_INOUT_DONE) ? DMA_INOUT_DONE : DMA_INOUT_ERROR; + rt_completion_done(&ce->dma_input_done); + + return; + } +} + +static void spacemit_crypto_free(struct spacemit_crypto *crypto, struct rt_device *dev) +{ + if (!rt_is_err_or_null(crypto->clk)) + { + rt_clk_disable_unprepare(crypto->clk); + rt_clk_put(crypto->clk); + } + + if (!rt_is_err_or_null(crypto->rstc)) + { + /* RESET_AES is shared with the eFuse and RNG blocks. */ + rt_reset_control_put(crypto->rstc); + } + + for (int i = 0; i < crypto->engine_nr; ++i) + { + struct spacemit_crypto_engine *ce = &crypto->engine[i]; + + if (ce->base) + { + rt_iounmap(ce->base); + } + + if (ce->in_buffer) + { + rt_dma_free_coherent(dev, SPACEMIT_AES_BUFFER_LEN, ce->in_buffer, ce->in_buffer_dma); + } + + if (ce->out_buffer) + { + rt_dma_free_coherent(dev, SPACEMIT_AES_BUFFER_LEN, ce->out_buffer, ce->out_buffer_dma); + } + + if (ce->crypto) + { + rt_mutex_detach(&ce->lock); + + if (rt_device_find(rt_dm_dev_get_name(&ce->parent.parent))) + { + rt_hw_interrupt_mask(ce->irq); + rt_pic_detach_irq(ce->irq, ce); + + rt_device_unregister(&ce->parent.parent); + } + } + } + + rt_free(crypto); +} + +static rt_err_t spacemit_crypto_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + char name[32]; + struct rt_device *dev = &pdev->parent; + struct spacemit_crypto *crypto = rt_calloc(1, sizeof(*crypto)); + + if (!crypto) + { + return -RT_ENOMEM; + } + + if ((err = rt_dm_dev_prop_read_u32(dev, "num-engines", &crypto->engine_nr))) + { + goto _fail; + } + + if (!(crypto->ciu_regmap = rt_syscon_find_by_ofw_compatible("spacemit,ciu"))) + { + err = -RT_EIO; + goto _fail; + } + + crypto->clk = rt_clk_get_by_index(dev, 0); + if (rt_is_err(crypto->clk)) + { + err = rt_ptr_err(crypto->clk); + goto _fail; + } + rt_clk_prepare_enable(crypto->clk); + + crypto->rstc = rt_reset_control_get_by_index(dev, 0); + if (rt_is_err(crypto->rstc)) + { + err = rt_ptr_err(crypto->rstc); + goto _fail; + } + rt_reset_control_deassert(crypto->rstc); + + for (int i = 0; i < crypto->engine_nr; ++i) + { + rt_uint32_t addr_range[2]; + struct spacemit_crypto_engine *ce = &crypto->engine[i]; + + rt_snprintf(name, sizeof(name), "spacemit-crypto-engine-%d", i); + + if ((err = rt_dm_dev_prop_read_u32_array_index(dev, name, 0, 2, &addr_range[0])) <= 0) + { + goto _fail; + } + + if (!(ce->base = rt_ioremap((void *)(rt_ubase_t)addr_range[0], addr_range[1]))) + { + err = -RT_EIO; + goto _fail; + } + + if ((ce->irq = rt_dm_dev_get_irq(dev, i)) < 0) + { + err = ce->irq; + goto _fail; + } + + ce->in_buffer = rt_dma_alloc_coherent(dev, SPACEMIT_AES_BUFFER_LEN, &ce->in_buffer_dma); + if (!ce->in_buffer) + { + err = -RT_ENOMEM; + goto _fail; + } + + ce->out_buffer = rt_dma_alloc_coherent(dev, SPACEMIT_AES_BUFFER_LEN, &ce->out_buffer_dma); + if (!ce->out_buffer) + { + err = -RT_ENOMEM; + goto _fail; + } + + ce->crypto = crypto; + + rt_completion_init(&ce->aes_done); + rt_completion_init(&ce->dma_output_done); + rt_completion_init(&ce->dma_input_done); + + rt_snprintf(name, sizeof(name), "%s%d", RT_HWCRYPTO_DEFAULT_NAME, i); + rt_mutex_init(&ce->lock, name, RT_IPC_FLAG_PRIO); + + ce->parent.ops = &spacemit_crypto_ops; + ce->parent.id = __LINE__; + + if ((err = rt_hwcrypto_register(&ce->parent, name))) + { + goto _fail; + } + + rt_hw_interrupt_install(ce->irq, spacemit_crypto_isr, ce, name); + rt_hw_interrupt_umask(ce->irq); + } + + rt_syscon_update_bits(crypto->ciu_regmap, ENGINE_DMA_ADDR_HIGH_OFFSET, + SW_RESETN | MASTER_CLK_EN | SLAVE_CLK_EN, + SW_RESETN | MASTER_CLK_EN | SLAVE_CLK_EN); + + dev->user_data = crypto; + + return RT_EOK; + +_fail: + spacemit_crypto_free(crypto, dev); + + return err; +} + +static rt_err_t spacemit_crypto_remove(struct rt_platform_device *pdev) +{ + struct rt_device *dev = &pdev->parent; + struct spacemit_crypto *crypto = dev->user_data; + + spacemit_crypto_free(crypto, dev); + + return RT_EOK; +} + +static const struct rt_ofw_node_id spacemit_crypto_ofw_ids[] = +{ + { .compatible = "spacemit,crypto_engine" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_crypto_driver = +{ + .name = "hwcrypto-spacemit", + .ids = spacemit_crypto_ofw_ids, + + .probe = spacemit_crypto_probe, + .remove = spacemit_crypto_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(spacemit_crypto_driver); diff --git a/bsp/spacemit/dm/hwcrypto/hw-rng-spacemit.c b/bsp/spacemit/dm/hwcrypto/hw-rng-spacemit.c new file mode 100644 index 000000000000..682f3810057e --- /dev/null +++ b/bsp/spacemit/dm/hwcrypto/hw-rng-spacemit.c @@ -0,0 +1,353 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include + +#include "spacemit.h" + +#define DBG_TAG "hwrng.spacemit" +#define DBG_LVL DBG_INFO +#include + +#define RNG_BYTE_CNT 0x04 +#define RNG_SRC_ADDR 0x14 +#define RNG_DEST_ADDR 0x24 +#define RNG_NEXT_DESC_PTR 0x34 +#define RNG_SQU_CTRL 0x44 +#define RNG_CURR_DESC_PTR 0x74 +#define RNG_INT_MASK 0x84 +#define RNG_REST_SEL 0x94 +#define RNG_INT_STATUS 0xa4 +#define RNG_CTRL 0xc0 +#define RNG_DATA 0xc4 +#define RNG_SEED_VAL 0xc8 +#define RNG_CTRL_EXT 0xd0 + +#define SQU_CTRL_FIFO_CLR RT_BIT(30) +#define SQU_CTRL_ENABLE_DMA 0x03c60383 +#define RNG_INT_DONE_MASK RT_BIT(0) +#define RESET_SEL_MASK RT_BIT(0) +#define CTRL_RNG_EN RT_BIT(0) +#define CTRL_RNG_VALID RT_BIT(31) +#define CTRL_RNG_SEED_VALID RT_BIT(30) +#define CTRL_RNG_SEED_EN RT_BIT(1) +#define RNG_REG_SEL RT_BIT(4) +#define RNG_REG_LDO_PU RT_BIT(6) +#define RNG_SUCCESS 0x55 +#define RNG_FAIL 0xaa + +#define DMA_MAX_SIZE 0xfff0 +#define RNG_TIMEOUT_MS 100 +#define RNG_POLL_DELAY_US 200 +#define RNG_RETRY_COUNT 2 + +struct spacemit_rng +{ + struct rt_hwcrypto_device parent; + + void *base; + struct rt_clk *clk; + struct rt_reset_control *rstc; + + struct rt_mutex lock; + rt_bool_t lock_ready; + rt_bool_t clk_enabled; +}; + +static void spacemit_rng_clr_fifo(struct spacemit_rng *rng) +{ + rt_uint32_t val; + + val = HWREG32(rng->base + RNG_SQU_CTRL); + val |= SQU_CTRL_FIFO_CLR; + HWREG32(rng->base + RNG_SQU_CTRL) = val; +} + +static void spacemit_rng_reset_status(struct spacemit_rng *rng) +{ + rt_uint32_t val; + + /* Clear squ fifo */ + spacemit_rng_clr_fifo(rng); + + /* Clear rng and seed ctrl bit */ + val = HWREG32(rng->base + RNG_CTRL); + val &= ~(CTRL_RNG_EN | CTRL_RNG_VALID); + val &= ~(CTRL_RNG_SEED_EN | CTRL_RNG_SEED_VALID); + HWREG32(rng->base + RNG_CTRL) = val; +} + +static rt_err_t spacemit_rng_wait_valid(struct spacemit_rng *rng, + rt_uint32_t mask) +{ + rt_tick_t start = rt_tick_get(); + rt_tick_t timeout = rt_tick_from_millisecond(RNG_TIMEOUT_MS); + + do { + if (HWREG32(rng->base + RNG_CTRL) & mask) + { + return RT_EOK; + } + + if ((rt_tick_t)(rt_tick_get() - start) >= timeout) + { + return -RT_ETIMEOUT; + } + + rt_hw_us_delay(RNG_POLL_DELAY_US); + } while (RT_TRUE); +} + +static rt_err_t spacemit_rng_reset_seed(struct spacemit_rng *rng) +{ + rt_uint32_t val; + + for (int i = 0; i < RNG_RETRY_COUNT; ++i) + { + spacemit_rng_reset_status(rng); + + /* Generate software seed */ + HWREG32(rng->base + RNG_SEED_VAL) = rt_tick_get() + i; + + val = HWREG32(rng->base + RNG_CTRL); + val |= CTRL_RNG_SEED_EN; + HWREG32(rng->base + RNG_CTRL) = val; + + if (!spacemit_rng_wait_valid(rng, CTRL_RNG_SEED_VALID)) + { + return RT_EOK; + } + + LOG_W("RNG seed generation timed out, retry %d/%d", + i + 1, RNG_RETRY_COUNT); + } + + spacemit_rng_reset_status(rng); + + return -RT_ETIMEOUT; +} + +static rt_uint32_t spacemit_rng_rand(struct hwcrypto_rng *ctx) +{ + rt_err_t err; + rt_uint32_t val = 0; + struct spacemit_rng *rng = rt_container_of(ctx->parent.device, struct spacemit_rng, parent); + + if ((err = rt_mutex_take(&rng->lock, RT_WAITING_FOREVER))) + { + LOG_E("take RNG lock failed: %s", rt_strerror(err)); + return 0; + } + + for (int i = 0; i < RNG_RETRY_COUNT; ++i) + { + if ((err = spacemit_rng_reset_seed(rng))) + { + LOG_E("RNG seed generation failed: %s", rt_strerror(err)); + break; + } + + /* Generate random value */ + val = HWREG32(rng->base + RNG_CTRL); + val |= CTRL_RNG_EN; + HWREG32(rng->base + RNG_CTRL) = val; + + if (!spacemit_rng_wait_valid(rng, CTRL_RNG_VALID)) + { + spacemit_rng_clr_fifo(rng); + val = HWREG32(rng->base + RNG_DATA); + goto _unlock; + } + + LOG_W("RNG value generation timed out, retry %d/%d", + i + 1, RNG_RETRY_COUNT); + } + + val = 0; + LOG_E("RNG value generation failed: ETIMOUT"); + +_unlock: + spacemit_rng_reset_status(rng); + rt_mutex_release(&rng->lock); + + return val; +} + +static const struct hwcrypto_rng_ops rng_ops = +{ + .update = spacemit_rng_rand, +}; + +static rt_err_t spacemit_rng_create(struct rt_hwcrypto_ctx *ctx) +{ + if ((ctx->type & HWCRYPTO_MAIN_TYPE_MASK) == HWCRYPTO_TYPE_RNG) + { + struct hwcrypto_rng *rng; + + ctx->contex = RT_NULL; + + rng = rt_container_of(ctx, struct hwcrypto_rng, parent); + rng->ops = &rng_ops; + + return RT_EOK; + } + + return -RT_ENOSYS; +} + +static void spacemit_rng_destroy(struct rt_hwcrypto_ctx *ctx) +{ +} + +static rt_err_t spacemit_rng_copy(struct rt_hwcrypto_ctx *des, + const struct rt_hwcrypto_ctx *src) +{ + if ((src->type & HWCRYPTO_MAIN_TYPE_MASK) == HWCRYPTO_TYPE_RNG) + { + return RT_EOK; + } + + return -RT_ENOSYS; +} + +static void spacemit_rng_reset(struct rt_hwcrypto_ctx *ctx) +{ +} + +static const struct rt_hwcrypto_ops spacemit_rng_ops = +{ + .create = spacemit_rng_create, + .destroy = spacemit_rng_destroy, + .copy = spacemit_rng_copy, + .reset = spacemit_rng_reset, +}; + +static void spacemit_crypto_free(struct spacemit_rng *rng) +{ + if (rng->base) + { + rt_iounmap(rng->base); + } + + if (!rt_is_err_or_null(rng->rstc)) + { + /* RESET_AES is shared with the crypto and eFuse blocks. */ + rt_reset_control_put(rng->rstc); + } + + if (!rt_is_err_or_null(rng->clk)) + { + if (rng->clk_enabled) + { + rt_clk_disable_unprepare(rng->clk); + } + rt_clk_put(rng->clk); + } + + if (rng->lock_ready) + { + rt_mutex_detach(&rng->lock); + } + + rt_free(rng); +} + +static rt_err_t spacemit_rng_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct spacemit_rng *rng = rt_calloc(1, sizeof(*rng)); + + if (!rng) + { + return -RT_ENOMEM; + } + + if ((err = rt_mutex_init(&rng->lock, "hwrng", RT_IPC_FLAG_PRIO))) + { + goto _fail; + } + rng->lock_ready = RT_TRUE; + + rng->clk = rt_clk_get_by_index(dev, 0); + if (rt_is_err_or_null(rng->clk)) + { + err = rng->clk ? rt_ptr_err(rng->clk) : -RT_ENOENT; + goto _fail; + } + if ((err = rt_clk_prepare_enable(rng->clk))) + { + goto _fail; + } + rng->clk_enabled = RT_TRUE; + + rng->rstc = rt_reset_control_get_by_index(dev, 0); + if (rt_is_err_or_null(rng->rstc)) + { + err = rng->rstc ? rt_ptr_err(rng->rstc) : -RT_ENOENT; + goto _fail; + } + if ((err = rt_reset_control_deassert(rng->rstc))) + { + goto _fail; + } + + rng->base = rt_dm_dev_iomap(dev, 0); + if (!rng->base) + { + err = -RT_EIO; + goto _fail; + } + + rng->parent.ops = &spacemit_rng_ops; + rng->parent.id = __LINE__; + + if ((err = rt_hwcrypto_register(&rng->parent, "hwrng"))) + { + goto _fail; + } + + dev->user_data = rng; + + return RT_EOK; + +_fail: + spacemit_crypto_free(rng); + + return err; +} + +static rt_err_t spacemit_rng_remove(struct rt_platform_device *pdev) +{ + struct spacemit_rng *rng = pdev->parent.user_data; + + rt_device_unregister(&rng->parent.parent); + + spacemit_crypto_free(rng); + + return RT_EOK; +} + +static const struct rt_ofw_node_id spacemit_rng_ofw_ids[] = +{ + { .compatible = "spacemit,hw_crng" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_rng_driver = +{ + .name = "hwrng-spacemit", + .ids = spacemit_rng_ofw_ids, + + .probe = spacemit_rng_probe, + .remove = spacemit_rng_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(spacemit_rng_driver); diff --git a/bsp/spacemit/dm/i2c/Kconfig b/bsp/spacemit/dm/i2c/Kconfig new file mode 100644 index 000000000000..b8821169dbcb --- /dev/null +++ b/bsp/spacemit/dm/i2c/Kconfig @@ -0,0 +1,3 @@ +config RT_I2C_SPACEMIT_K1X + bool "Spacemit k1x I2C controller" + default n diff --git a/bsp/spacemit/dm/i2c/SConscript b/bsp/spacemit/dm/i2c/SConscript new file mode 100644 index 000000000000..3f36c4f80bdd --- /dev/null +++ b/bsp/spacemit/dm/i2c/SConscript @@ -0,0 +1,13 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_I2C_SPACEMIT_K1X']): + src += ['i2c-k1x.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/i2c/i2c-k1x.c b/bsp/spacemit/dm/i2c/i2c-k1x.c new file mode 100644 index 000000000000..ed4b32f9c43f --- /dev/null +++ b/bsp/spacemit/dm/i2c/i2c-k1x.c @@ -0,0 +1,1411 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include +#include + +#define DBG_TAG "i2c.rk3x" +#define DBG_LVL DBG_INFO +#include + +#include + +/* Spacemit i2c registers */ +#define REG_CR 0x0 /* Control Register */ +#define REG_SR 0x4 /* Status Register */ +#define REG_SAR 0x8 /* Slave Address Register */ +#define REG_DBR 0xc /* Data Buffer Register */ +#define REG_LCR 0x10 /* Load Count Register */ +#define REG_WCR 0x14 /* Wait Count Register */ +#define REG_RST_CYC 0x18 /* Bus reset cycle counter */ +#define REG_BMR 0x1c /* Bus monitor register */ +#define REG_WFIFO 0x20 /* Write FIFO Register */ +#define REG_WFIFO_WPTR 0x24 /* Write FIFO Write Pointer Register */ +#define REG_WFIFO_RPTR 0x28 /* Write FIFO Read Pointer Register */ +#define REG_RFIFO 0x2c /* Read FIFO Register */ +#define REG_RFIFO_WPTR 0x30 /* Read FIFO Write Pointer Register */ +#define REG_RFIFO_RPTR 0x34 /* Read FIFO Read Pointer Register */ + +/* Register REG_CR fields */ +#define CR_START RT_BIT(0) /* Start bit */ +#define CR_STOP RT_BIT(1) /* Stop bit */ +#define CR_ACKNAK RT_BIT(2) /* Send ACK(0) or NAK(1) */ +#define CR_TB RT_BIT(3) /* Transfer byte bit */ +#define CR_TXBEGIN RT_BIT(4) /* Transaction begin */ +#define CR_FIFOEN RT_BIT(5) /* Enable FIFO mode */ +#define CR_GPIOEN RT_BIT(6) /* Enable GPIO mode for SCL in HS */ +#define CR_DMAEN RT_BIT(7) /* Enable DMA for TX and RX FIFOs */ +#define CR_MODE_FAST RT_BIT(8) /* Bus mode (master operation) */ +#define CR_MODE_HIGH RT_BIT(9) /* Bus mode (master operation) */ +#define CR_UR RT_BIT(10) /* Unit reset */ +#define CR_RSTREQ RT_BIT(11) /* I2c bus reset request */ +#define CR_MA RT_BIT(12) /* Master abort */ +#define CR_SCLE RT_BIT(13) /* Master clock enable */ +#define CR_IUE RT_BIT(14) /* Unit enable */ +#define CR_HS_STRETCH RT_BIT(16) /* I2C hs stretch */ +#define CR_ALDIE RT_BIT(18) /* Enable arbitration interrupt */ +#define CR_DTEIE RT_BIT(19) /* Enable tx interrupts */ +#define CR_DRFIE RT_BIT(20) /* Enable rx interrupts */ +#define CR_GCD RT_BIT(21) /* General call disable */ +#define CR_BEIE RT_BIT(22) /* Enable bus error ints */ +#define CR_SADIE RT_BIT(23) /* Slave address detected int enable */ +#define CR_SSDIE RT_BIT(24) /* Slave STOP detected int enable */ +#define CR_MSDIE RT_BIT(25) /* Master STOP detected int enable */ +#define CR_MSDE RT_BIT(26) /* Master STOP detected enable */ +#define CR_TXDONEIE RT_BIT(27) /* Transaction done int enable */ +#define CR_TXEIE RT_BIT(28) /* Transmit FIFO empty int enable */ +#define CR_RXHFIE RT_BIT(29) /* Receive FIFO half-full int enable */ +#define CR_RXFIE RT_BIT(30) /* Receive FIFO full int enable */ +#define CR_RXOVIE RT_BIT(31) /* Receive FIFO overrun int enable */ + +/* Register REG_SR fields */ +#define SR_RWM RT_BIT(13) /* Read/write mode */ +#define SR_ACKNAK RT_BIT(14) /* ACK/NACK status */ +#define SR_UB RT_BIT(15) /* Unit busy */ +#define SR_IBB RT_BIT(16) /* I2c bus busy */ +#define SR_EBB RT_BIT(17) /* Early bus busy */ +#define SR_ALD RT_BIT(18) /* Arbitration loss detected */ +#define SR_ITE RT_BIT(19) /* Tx buffer empty */ +#define SR_IRF RT_BIT(20) /* Rx buffer full */ +#define SR_GCAD RT_BIT(21) /* General call address detected */ +#define SR_BED RT_BIT(22) /* Bus error no ACK/NAK */ +#define SR_SAD RT_BIT(23) /* Slave address detected */ +#define SR_SSD RT_BIT(24) /* Slave stop detected */ +#define SR_MSD RT_BIT(26) /* Master stop detected */ +#define SR_TXDONE RT_BIT(27) /* Transaction done */ +#define SR_TXE RT_BIT(28) /* Tx FIFO empty */ +#define SR_RXHF RT_BIT(29) /* Rx FIFO half-full */ +#define SR_RXF RT_BIT(30) /* Rx FIFO full */ +#define SR_RXOV RT_BIT(31) /* RX FIFO overrun */ + +/* Register REG_LCR fields */ +#define LCR_SLV 0x000001ff /* SLV: bit[8:0] */ +#define LCR_FLV 0x0003fe00 /* FLV: bit[17:9] */ +#define LCR_HLVH 0x07fc0000 /* HLVH: bit[26:18] */ +#define LCR_HLVL 0xf8000000 /* HLVL: bit[31:27] */ + +/* Register REG_WCR fields */ +#define WCR_COUNT 0x0000001f /* COUNT: bit[4:0] */ +#define WCR_COUNT1 0x000003e0 /* HS_COUNT1: bit[9:5] */ +#define WCR_COUNT2 0x00007c00 /* HS_COUNT2: bit[14:10] */ + +/* Register REG_BMR fields */ +#define BMR_SDA RT_BIT(0) /* SDA line level */ +#define BMR_SCL RT_BIT(1) /* SCL line level */ + +/* Register REG_WFIFO fields */ +#define WFIFO_DATA_MSK 0x000000ff /* data: bit[7:0] */ +#define WFIFO_CTRL_MSK 0x000003e0 /* control: bit[11:8] */ +#define WFIFO_CTRL_START RT_BIT(8) /* start bit */ +#define WFIFO_CTRL_STOP RT_BIT(9) /* stop bit */ +#define WFIFO_CTRL_ACKNAK RT_BIT(10) /* send ACK(0) or NAK(1) */ +#define WFIFO_CTRL_TB RT_BIT(11) /* transfer byte bit */ + +#define USEC_PER_SEC 1000000L +#define USEC_PER_MSEC 1000L +#define I2C_SMBUS_BLOCK_MAX 32 + +/* Status register init value */ +#define SPACEMIT_I2C_INT_STATUS_MASK 0xfffc0000 /* SR bits[31:18] */ +#define SPACEMIT_I2C_INT_CTRL_MASK (CR_ALDIE | CR_DTEIE | CR_DRFIE | CR_BEIE | CR_TXDONEIE | \ + CR_TXEIE | CR_RXHFIE | CR_RXFIE | CR_RXOVIE | CR_MSDIE) + +/* I2C transfer mode */ +enum spacemit_i2c_xfer_mode +{ + SPACEMIT_I2C_MODE_INTERRUPT, + SPACEMIT_I2C_MODE_FIFO, + SPACEMIT_I2C_MODE_DMA, + SPACEMIT_I2C_MODE_PIO, + SPACEMIT_I2C_MODE_INVALID, +}; + +/* I2C transfer phase during transaction */ +enum spacemit_i2c_xfer_phase +{ + SPACEMIT_I2C_XFER_MASTER_CODE, + SPACEMIT_I2C_XFER_SLAVE_ADDR, + SPACEMIT_I2C_XFER_BODY, + SPACEMIT_I2C_XFER_IDLE, +}; + +/* i2c controller FIFO depth */ +#define SPACEMIT_I2C_RX_FIFO_DEPTH 8 +#define SPACEMIT_I2C_TX_FIFO_DEPTH 8 + +/* i2c bus recover timeout: us */ +#define SPACEMIT_I2C_BUS_RECOVER_TIMEOUT 100000 + +/* i2c bus active timeout: us */ +#define SPACEMIT_I2C_BUS_ACTIVE_TIMEOUT 100000 + +/* scatter list size for DMA mode, equals to max number of i2c messages */ +#define SPACEMIT_I2C_SCATTERLIST_SIZE 42 + +/* for DMA mode, limit one message's length less than 512 bytes */ +#define SPACEMIT_I2C_MAX_MSG_LEN 512 +#define SPACEMIT_I2C_DMA_TX_BUF_LEN ((SPACEMIT_I2C_MAX_MSG_LEN + 2) * SPACEMIT_I2C_SCATTERLIST_SIZE) +#define SPACEMIT_I2C_DMA_RX_BUF_LEN (SPACEMIT_I2C_MAX_MSG_LEN * SPACEMIT_I2C_SCATTERLIST_SIZE) + +#define SPACEMIT_I2C_APB_CLOCK_26M 26000000 +#define SPACEMIT_I2C_APB_CLOCK_52M 52000000 + +#define I2C_SDA_GLITCH_FIX_BYPASS RT_BIT(7) + +/* i2c-spacemit driver's main struct */ +struct spacemit_i2c +{ + struct rt_i2c_bus_device parent; + + int irq; + void *regs; + struct rt_clk *clk; + struct rt_reset_control *rstc; + + rt_uint32_t drv_retries; + + rt_bool_t clk_always_on; + rt_bool_t dma_disable; + + /* Speed mode selection */ + rt_bool_t fast_mode; + rt_bool_t high_mode; + + /* APB clock */ + rt_uint32_t apb_clock; + + /* Master code for high-speed mode */ + rt_uint8_t master_code; + rt_uint32_t clk_rate; + rt_uint32_t i2c_lcr; + rt_uint32_t i2c_wcr; + + /* Slave address with read/write flag */ + rt_uint32_t slave_addr_rw; + + struct rt_i2c_msg *msgs; + int num; + + struct rt_i2c_msg *cur_msg; + int msg_idx; + + rt_uint8_t *msg_buf; + rt_bool_t is_rx; + rt_size_t rx_cnt; + rt_size_t tx_cnt; + int rx_total; + rt_bool_t is_xfer_start; + + struct rt_completion complete; + struct rt_spinlock fifo_lock; + + rt_tick_t timeout; + enum spacemit_i2c_xfer_mode xfer_mode; + enum spacemit_i2c_xfer_phase phase; + rt_uint32_t i2c_ctrl_reg_value; + rt_uint32_t i2c_status; + rt_uint32_t i2c_err; +}; + +#define raw_to_spacemit_i2c(raw) rt_container_of(raw, struct spacemit_i2c, parent) + +static rt_err_t spacemit_i2c_byte_xfer(struct spacemit_i2c *i2c); +static rt_err_t spacemit_i2c_byte_xfer_next_msg(struct spacemit_i2c *i2c); + +rt_inline rt_uint32_t spacemit_i2c_read(struct spacemit_i2c *i2c, int offset) +{ + return HWREG32(i2c->regs + offset); +} + +rt_inline void spacemit_i2c_write(struct spacemit_i2c *i2c, int offset, rt_uint32_t val) +{ + HWREG32(i2c->regs + offset) = val; +} + +static void spacemit_i2c_enable(struct spacemit_i2c *i2c) +{ + spacemit_i2c_write(i2c, REG_CR, spacemit_i2c_read(i2c, REG_CR) | CR_IUE); +} + +static void spacemit_i2c_disable(struct spacemit_i2c *i2c) +{ + i2c->i2c_ctrl_reg_value = spacemit_i2c_read(i2c, REG_CR) & ~CR_IUE; + spacemit_i2c_write(i2c, REG_CR, i2c->i2c_ctrl_reg_value); +} + +static void spacemit_i2c_flush_fifo_buffer(struct spacemit_i2c *i2c) +{ + /* Flush REG_WFIFO_WPTR and REG_WFIFO_RPTR */ + spacemit_i2c_write(i2c, REG_WFIFO_WPTR, 0); + spacemit_i2c_write(i2c, REG_WFIFO_RPTR, 0); + + /* Flush REG_RFIFO_WPTR and REG_RFIFO_RPTR */ + spacemit_i2c_write(i2c, REG_RFIFO_WPTR, 0); + spacemit_i2c_write(i2c, REG_RFIFO_RPTR, 0); +} + +static void spacemit_i2c_controller_reset(struct spacemit_i2c *i2c) +{ + /* Controller reset */ + spacemit_i2c_write(i2c, REG_CR, CR_UR); + rt_hw_us_delay(5); + spacemit_i2c_write(i2c, REG_CR, 0); + + /* Set load counter register */ + if (i2c->i2c_lcr) + { + spacemit_i2c_write(i2c, REG_LCR, i2c->i2c_lcr); + } + + /* Set wait counter register */ + if (i2c->i2c_wcr) + { + spacemit_i2c_write(i2c, REG_WCR, i2c->i2c_wcr); + } +} + +static void spacemit_i2c_bus_reset(struct spacemit_i2c *i2c) +{ + rt_uint32_t bus_status, val; + + /* If bus is locked, reset unit. 0: locked */ + bus_status = spacemit_i2c_read(i2c, REG_BMR); + if (!(bus_status & BMR_SDA) || !(bus_status & BMR_SCL)) + { + spacemit_i2c_controller_reset(i2c); + rt_hw_us_delay(15); + } + + for (int clk_cnt = 0; clk_cnt < 9; ++clk_cnt) + { + /* check whether the SDA is still locked by slave */ + bus_status = spacemit_i2c_read(i2c, REG_BMR); + if (bus_status & BMR_SDA) + { + break; + } + + /* If still locked, send one clk to slave to request release */ + val = spacemit_i2c_read(i2c, REG_RST_CYC); + spacemit_i2c_write(i2c, REG_RST_CYC, val | 0x1); + spacemit_i2c_write(i2c, REG_CR, CR_RSTREQ); + rt_hw_us_delay(25); + } +} + +static void spacemit_i2c_reset(struct spacemit_i2c *i2c) +{ + spacemit_i2c_controller_reset(i2c); +} + +static rt_err_t spacemit_i2c_recover_bus_busy(struct spacemit_i2c *i2c) +{ + rt_err_t err; + int cnt, timeout = i2c->high_mode ? 1000 : 1500; /* us */ + + cnt = SPACEMIT_I2C_BUS_RECOVER_TIMEOUT / timeout; + + if (!(spacemit_i2c_read(i2c, REG_SR) & (SR_UB | SR_IBB))) + { + return RT_EOK; + } + + /* Wait unit and bus to recover idle */ + while (spacemit_i2c_read(i2c, REG_SR) & (SR_UB | SR_IBB)) + { + if (cnt-- <= 0) + { + break; + } + + rt_hw_us_delay((timeout / 2 + timeout) / 2); + } + + if (cnt <= 0) + { + /* Reset controller */ + spacemit_i2c_reset(i2c); + err = -RT_EIO; + } + else + { + err = RT_EOK; + } + + return err; +} + +static void spacemit_i2c_check_bus_release(struct spacemit_i2c *i2c) +{ + /* In case bus is not released after transfer completes */ + if (spacemit_i2c_read(i2c, REG_SR) & SR_EBB) + { + spacemit_i2c_bus_reset(i2c); + rt_hw_us_delay(120); + } +} + +static void spacemit_i2c_unit_init(struct spacemit_i2c *i2c) +{ + rt_uint32_t cr_val = 0; + + /* + * Unmask interrupt bits for all xfer mode: + * bus error, arbitration loss detected. + * For transaction complete signal, we use master stop + * interrupt, so we don't need to unmask CR_TXDONEIE. + */ + cr_val |= CR_BEIE | CR_ALDIE; + + if (i2c->xfer_mode == SPACEMIT_I2C_MODE_INTERRUPT) + { + /* + * Unmask interrupt bits for interrupt xfer mode: DBR rx full. + * For tx empty interrupt CR_DTEIE, we only need to enable when + * trigger byte transfer to start data sending. + */ + cr_val |= CR_DRFIE; + } + else if (i2c->xfer_mode == SPACEMIT_I2C_MODE_FIFO) + { + /* Enable i2c FIFO mode*/ + cr_val |= CR_FIFOEN; + } + else if (i2c->xfer_mode == SPACEMIT_I2C_MODE_DMA) + { + /* Enable i2c DMA mode*/ + cr_val |= CR_DMAEN | CR_FIFOEN; + } + + /* Set speed bits */ + if (i2c->fast_mode) + { + cr_val |= CR_MODE_FAST; + } + if (i2c->high_mode) + { + cr_val |= CR_MODE_HIGH | CR_GPIOEN; + } + + /* Disable response to general call */ + cr_val |= CR_GCD; + + /* Enable SCL clock output */ + cr_val |= CR_SCLE; + + /* Enable master stop detected */ + cr_val |= CR_MSDE | CR_MSDIE; + + /* Disable int to use pio xfer mode*/ + if (i2c->xfer_mode == SPACEMIT_I2C_MODE_PIO) + { + cr_val &= ~(CR_ALDIE | CR_BEIE | CR_MSDIE | CR_DTEIE); + } + + spacemit_i2c_write(i2c, REG_CR, cr_val); +} + +static void spacemit_i2c_trigger_byte_xfer(struct spacemit_i2c *i2c) +{ + rt_uint32_t cr_val; + + /* Send start pulse */ + cr_val = spacemit_i2c_read(i2c, REG_CR); + cr_val &= ~CR_STOP; + if (i2c->xfer_mode == SPACEMIT_I2C_MODE_PIO) + { + cr_val |= CR_START | CR_TB; + } + else + { + cr_val |= CR_START | CR_TB | CR_DTEIE; + } + spacemit_i2c_write(i2c, REG_CR, cr_val); +} + +rt_inline void spacemit_i2c_clear_int_status(struct spacemit_i2c *i2c, rt_uint32_t mask) +{ + spacemit_i2c_write(i2c, REG_SR, mask & SPACEMIT_I2C_INT_STATUS_MASK); +} + +static rt_bool_t spacemit_i2c_is_last_byte_to_send(struct spacemit_i2c *i2c) +{ + return i2c->tx_cnt == i2c->cur_msg->len && i2c->msg_idx == i2c->num - 1; +} + +static rt_bool_t spacemit_i2c_is_last_byte_to_receive(struct spacemit_i2c *i2c) +{ + return i2c->rx_cnt == i2c->cur_msg->len - 1 && i2c->msg_idx == i2c->num - 1; +} + +static void spacemit_i2c_mark_rw_flag(struct spacemit_i2c *i2c) +{ + if (i2c->cur_msg->flags & RT_I2C_RD) + { + i2c->is_rx = RT_TRUE; + i2c->slave_addr_rw = ((i2c->cur_msg->addr & 0x7f) << 1) | 1; + } + else + { + i2c->is_rx = RT_FALSE; + i2c->slave_addr_rw = (i2c->cur_msg->addr & 0x7f) << 1; + } +} + +static void spacemit_i2c_byte_xfer_send_master_code(struct spacemit_i2c *i2c) +{ + rt_uint32_t cr_val = spacemit_i2c_read(i2c, REG_CR); + + i2c->phase = SPACEMIT_I2C_XFER_MASTER_CODE; + + spacemit_i2c_write(i2c, REG_DBR, i2c->master_code); + + cr_val &= ~(CR_STOP | CR_ALDIE); + + /* High mode: enable gpio to let I2C core generates SCL clock */ + cr_val |= CR_GPIOEN | CR_START | CR_TB | CR_DTEIE; + spacemit_i2c_write(i2c, REG_CR, cr_val); +} + +static void spacemit_i2c_byte_xfer_send_slave_addr(struct spacemit_i2c *i2c) +{ + i2c->phase = SPACEMIT_I2C_XFER_SLAVE_ADDR; + + /* Write slave address to DBR for interrupt mode */ + spacemit_i2c_write(i2c, REG_DBR, i2c->slave_addr_rw); + + spacemit_i2c_trigger_byte_xfer(i2c); +} + +static rt_err_t spacemit_i2c_byte_xfer_body(struct spacemit_i2c *i2c) +{ + rt_err_t err = RT_EOK; + rt_uint32_t cr_val = spacemit_i2c_read(i2c, REG_CR); + + cr_val &= ~(CR_TB | CR_ACKNAK | CR_STOP | CR_START); + i2c->phase = SPACEMIT_I2C_XFER_BODY; + + if (i2c->i2c_status & SR_IRF) /* Receive full */ + { + /* If current is transmit mode, ignore this signal */ + if (!i2c->is_rx) + { + return RT_EOK; + } + + if (i2c->rx_cnt < i2c->cur_msg->len) + { + *i2c->msg_buf++ = spacemit_i2c_read(i2c, REG_DBR); + i2c->rx_cnt++; + } + + /* If transfer completes, ISR will handle it */ + if (i2c->i2c_status & (SR_MSD | SR_ACKNAK)) + { + return RT_EOK; + } + + /* Trigger next byte receive */ + if (i2c->rx_cnt < i2c->cur_msg->len) + { + /* Send stop pulse for last byte of last msg */ + if (spacemit_i2c_is_last_byte_to_receive(i2c)) + { + cr_val |= CR_STOP | CR_ACKNAK; + } + + cr_val |= CR_ALDIE | CR_TB; + spacemit_i2c_write(i2c, REG_CR, cr_val); + } + else if (i2c->msg_idx < i2c->num - 1) + { + err = spacemit_i2c_byte_xfer_next_msg(i2c); + } + } + else if (i2c->i2c_status & SR_ITE) /* Transmit empty */ + { + /* MSD comes with ITE */ + if (i2c->i2c_status & SR_MSD) + { + return err; + } + + if (i2c->i2c_status & SR_RWM) /* Receive mode */ + { + /* If current is transmit mode, ignore this signal */ + if (!i2c->is_rx) + { + return RT_EOK; + } + + if (spacemit_i2c_is_last_byte_to_receive(i2c)) + { + cr_val |= CR_STOP | CR_ACKNAK; + } + + /* Trigger next byte receive */ + cr_val |= CR_ALDIE | CR_TB; + + /* + * Mask transmit empty interrupt to avoid useless tx + * interrupt signal after switch to receive mode, the + * next expected is receive full interrupt signal. + */ + cr_val &= ~CR_DTEIE; + spacemit_i2c_write(i2c, REG_CR, cr_val); + } + else /* Transmit mode */ + { + /* If current is receive mode, ignore this signal */ + if (i2c->is_rx) + { + return RT_EOK; + } + + if (i2c->tx_cnt < i2c->cur_msg->len) + { + spacemit_i2c_write(i2c, REG_DBR, *i2c->msg_buf++); + i2c->tx_cnt++; + + /* Send stop pulse for last byte of last msg */ + if (spacemit_i2c_is_last_byte_to_send(i2c)) + { + cr_val |= CR_STOP; + } + + cr_val |= CR_ALDIE | CR_TB; + spacemit_i2c_write(i2c, REG_CR, cr_val); + } + else if (i2c->msg_idx < i2c->num - 1) + { + err = spacemit_i2c_byte_xfer_next_msg(i2c); + } + } + } + + return err; +} + +static rt_err_t spacemit_i2c_byte_xfer_next_msg(struct spacemit_i2c *i2c) +{ + if (i2c->msg_idx == i2c->num - 1) + { + return RT_EOK; + } + + i2c->msg_idx++; + i2c->cur_msg = i2c->msgs + i2c->msg_idx; + i2c->msg_buf = i2c->cur_msg->buf; + i2c->rx_cnt = 0; + i2c->tx_cnt = 0; + i2c->i2c_err = 0; + i2c->i2c_status = 0; + i2c->phase = SPACEMIT_I2C_XFER_IDLE; + + spacemit_i2c_mark_rw_flag(i2c); + + return spacemit_i2c_byte_xfer(i2c); +} + +static void spacemit_i2c_fifo_xfer_fill_buffer(struct spacemit_i2c *i2c) +{ + rt_ubase_t level; + int data_cnt = 0, finish, count = 0, fill = 0; + rt_uint32_t data = 0, data_buf[SPACEMIT_I2C_TX_FIFO_DEPTH * 2]; + + while (i2c->msg_idx < i2c->num) + { + spacemit_i2c_mark_rw_flag(i2c); + + if (i2c->is_rx) + { + finish = i2c->rx_cnt; + } + else + { + finish = i2c->tx_cnt; + } + + /* Write master code to fifo buffer */ + if (i2c->high_mode && i2c->is_xfer_start) + { + data = i2c->master_code; + data |= WFIFO_CTRL_TB | WFIFO_CTRL_START; + data_buf[data_cnt++] = data; + + fill += 2; + count = rt_min_t(rt_size_t, i2c->cur_msg->len - finish, SPACEMIT_I2C_TX_FIFO_DEPTH - fill); + } + else + { + fill += 1; + count = rt_min_t(rt_size_t, i2c->cur_msg->len - finish, SPACEMIT_I2C_TX_FIFO_DEPTH - fill); + } + + i2c->is_xfer_start = RT_FALSE; + fill += count; + data = i2c->slave_addr_rw; + data |= WFIFO_CTRL_TB | WFIFO_CTRL_START; + + /* Write slave address to fifo buffer */ + data_buf[data_cnt++] = data; + + if (i2c->is_rx) + { + i2c->rx_cnt += count; + + if (i2c->rx_cnt == i2c->cur_msg->len && i2c->msg_idx == i2c->num - 1) + { + count -= 1; + } + + while (count > 0) + { + data = *i2c->msg_buf | WFIFO_CTRL_TB; + data_buf[data_cnt++] = data; + i2c->msg_buf++; + count--; + } + + if (i2c->rx_cnt == i2c->cur_msg->len && i2c->msg_idx == i2c->num - 1) + { + data = *i2c->msg_buf++; + data = i2c->slave_addr_rw | WFIFO_CTRL_TB | WFIFO_CTRL_STOP | WFIFO_CTRL_ACKNAK; + data_buf[data_cnt++] = data; + } + } + else + { + i2c->tx_cnt += count; + if (spacemit_i2c_is_last_byte_to_send(i2c)) + { + count -= 1; + } + + while (count > 0) + { + data = *i2c->msg_buf | WFIFO_CTRL_TB; + data_buf[data_cnt++] = data; + i2c->msg_buf++; + count--; + } + if (spacemit_i2c_is_last_byte_to_send(i2c)) + { + data = *i2c->msg_buf | WFIFO_CTRL_TB | WFIFO_CTRL_STOP; + data_buf[data_cnt++] = data; + } + } + + if (i2c->tx_cnt == i2c->cur_msg->len || i2c->rx_cnt == i2c->cur_msg->len) + { + i2c->msg_idx++; + if (i2c->msg_idx == i2c->num) + { + break; + } + + i2c->cur_msg = i2c->msgs + i2c->msg_idx; + i2c->msg_buf = i2c->cur_msg->buf; + i2c->rx_cnt = 0; + i2c->tx_cnt = 0; + } + + if (fill == SPACEMIT_I2C_TX_FIFO_DEPTH) + { + break; + } + } + + level = rt_spin_lock_irqsave(&i2c->fifo_lock); + + for (int i = 0; i < data_cnt; ++i) + { + spacemit_i2c_write(i2c, REG_WFIFO, data_buf[i]); + } + + rt_spin_unlock_irqrestore(&i2c->fifo_lock, level); +} + +static void spacemit_i2c_fifo_xfer_copy_buffer(struct spacemit_i2c *i2c) +{ + int idx = 0, cnt = 0; + struct rt_i2c_msg *msg; + + /* Copy the rx FIFO buffer to msg */ + while (idx < i2c->num) + { + msg = i2c->msgs + idx; + if (msg->flags & RT_I2C_RD) + { + cnt = msg->len; + while (cnt > 0) + { + *(msg->buf + msg->len - cnt) = spacemit_i2c_read(i2c, REG_RFIFO); + cnt--; + } + } + idx++; + } +} + +static rt_err_t spacemit_i2c_fifo_xfer(struct spacemit_i2c *i2c) +{ + rt_err_t err = RT_EOK; + + spacemit_i2c_fifo_xfer_fill_buffer(i2c); + + if ((err = rt_completion_wait(&i2c->complete, i2c->timeout))) + { + spacemit_i2c_bus_reset(i2c); + goto _err_out; + } + + if (i2c->i2c_err) + { + err = -RT_ERROR; + spacemit_i2c_flush_fifo_buffer(i2c); + goto _err_out; + } + + spacemit_i2c_fifo_xfer_copy_buffer(i2c); + +_err_out: + return err; +} + +static rt_err_t spacemit_i2c_byte_xfer(struct spacemit_i2c *i2c) +{ + rt_err_t err = RT_EOK; + + if (i2c->i2c_err) + { + return -RT_ERROR; + } + + if (i2c->phase == SPACEMIT_I2C_XFER_IDLE) + { + if (i2c->high_mode && i2c->is_xfer_start) + { + spacemit_i2c_byte_xfer_send_master_code(i2c); + } + else + { + spacemit_i2c_byte_xfer_send_slave_addr(i2c); + } + + i2c->is_xfer_start = RT_FALSE; + } + else if (i2c->phase == SPACEMIT_I2C_XFER_MASTER_CODE) + { + spacemit_i2c_byte_xfer_send_slave_addr(i2c); + } + else + { + err = spacemit_i2c_byte_xfer_body(i2c); + } + + return err; +} + +static void spacemit_i2c_choose_xfer_mode(struct spacemit_i2c *i2c) +{ + unsigned long timeout; + int idx = 0, cnt = 0, freq; + rt_bool_t block = RT_FALSE; + + /* Scan msgs */ + if (i2c->high_mode) + { + cnt++; + } + + i2c->rx_total = 0; + + while (idx < i2c->num) + { + cnt += (i2c->msgs + idx)->len + 1; + + if ((i2c->msgs + idx)->flags & RT_I2C_RD) + { + i2c->rx_total += (i2c->msgs + idx)->len; + } + + idx++; + } + + if (i2c->dma_disable || block) + { + i2c->xfer_mode = SPACEMIT_I2C_MODE_INTERRUPT; + } + else + { + if (cnt <= SPACEMIT_I2C_TX_FIFO_DEPTH) + { + i2c->xfer_mode = SPACEMIT_I2C_MODE_FIFO; + } + else + { + i2c->xfer_mode = SPACEMIT_I2C_MODE_DMA; + } + + /* Flush fifo buffer */ + spacemit_i2c_flush_fifo_buffer(i2c); + } + + /* + * if total message length is too large to over the allocated MDA + * total buf length, use interrupt mode. This may happens in the + * syzkaller test. + */ + if (cnt > (SPACEMIT_I2C_MAX_MSG_LEN * SPACEMIT_I2C_SCATTERLIST_SIZE) || + i2c->rx_total > SPACEMIT_I2C_DMA_RX_BUF_LEN) + { + i2c->xfer_mode = SPACEMIT_I2C_MODE_INTERRUPT; + } + + /* calculate timeout */ + if (i2c->high_mode) + { + freq = 1500000; + } + else if (i2c->fast_mode) + { + freq = 400000; + } + else + { + freq = 100000; + } + + timeout = cnt * 9 * USEC_PER_SEC / freq; + + if (i2c->xfer_mode == SPACEMIT_I2C_MODE_INTERRUPT || + i2c->xfer_mode == SPACEMIT_I2C_MODE_PIO) + { + timeout += (cnt - 1) * 220; + } + + timeout /= USEC_PER_MSEC; + + if (i2c->xfer_mode == SPACEMIT_I2C_MODE_INTERRUPT) + { + i2c->timeout = rt_tick_from_millisecond(timeout + 500); + } + else + { + i2c->timeout = rt_tick_from_millisecond(timeout + 100); + } +} + +static void spacemit_i2c_init_xfer_params(struct spacemit_i2c *i2c) +{ + /* Initialize transfer parameters */ + i2c->msg_idx = 0; + i2c->cur_msg = i2c->msgs; + i2c->msg_buf = i2c->cur_msg->buf; + i2c->rx_cnt = 0; + i2c->tx_cnt = 0; + i2c->i2c_err = 0; + i2c->i2c_status = 0; + i2c->phase = SPACEMIT_I2C_XFER_IDLE; + + /* Only send master code once for high speed mode */ + i2c->is_xfer_start = RT_TRUE; +} + +rt_used +static rt_ssize_t spacemit_i2c_pio_xfer(struct spacemit_i2c *i2c) +{ + rt_ssize_t res; + int xfer_try = 0; + rt_uint32_t status; + signed long timeout; + +_xfer_retry: + /* calculate timeout */ + spacemit_i2c_choose_xfer_mode(i2c); + i2c->xfer_mode = SPACEMIT_I2C_MODE_PIO; + timeout = i2c->timeout * (1000U / RT_TICK_PER_SECOND) * USEC_PER_MSEC; + + if (!i2c->clk_always_on) + { + rt_clk_enable(i2c->clk); + } + + spacemit_i2c_controller_reset(i2c); + rt_hw_us_delay(2); + + spacemit_i2c_unit_init(i2c); + + spacemit_i2c_clear_int_status(i2c, SPACEMIT_I2C_INT_STATUS_MASK); + + spacemit_i2c_init_xfer_params(i2c); + + spacemit_i2c_mark_rw_flag(i2c); + + spacemit_i2c_enable(i2c); + + if ((res = spacemit_i2c_byte_xfer(i2c)) < 0) + { + goto _out; + } + + while (i2c->num > 0 && timeout > 0) + { + status = spacemit_i2c_read(i2c, REG_SR); + spacemit_i2c_clear_int_status(i2c, status); + i2c->i2c_status = status; + + /* Bus error, arbitration lost */ + i2c->i2c_err = status & (SR_BED | SR_ALD); + if (i2c->i2c_err) + { + res = -RT_ERROR; + break; + } + + /* Receive full */ + if (status & SR_IRF) + { + if ((res = spacemit_i2c_byte_xfer(i2c)) < 0) + { + break; + } + } + + /* Transmit empty */ + if (status & SR_ITE) + { + if ((res = spacemit_i2c_byte_xfer(i2c)) < 0) + { + break; + } + } + + /* Transaction done */ + if (status & SR_MSD) + { + break; + } + + rt_hw_us_delay(10); + timeout -= 10; + } + + spacemit_i2c_disable(i2c); + + if (!i2c->clk_always_on) + { + rt_clk_disable(i2c->clk); + } + + if (timeout <= 0) + { + spacemit_i2c_bus_reset(i2c); + rt_hw_us_delay(100); + res = -RT_ETIMEOUT; + goto _out; + } + + /* Process i2c error */ + if (i2c->i2c_err) + { + res = -RT_EIO; + } + +_out: + xfer_try++; + /* Retry i2c transfer 3 times for timeout and bus busy */ + if ((res == -RT_ETIMEOUT || res == -RT_EIO) && xfer_try <= i2c->drv_retries) + { + rt_hw_us_delay(150); + res = 0; + goto _xfer_retry; + } + + return res < 0 ? res : i2c->num; +} + +static rt_ssize_t spacemit_i2c_xfer(struct rt_i2c_bus_device *bus, + struct rt_i2c_msg msgs[], rt_uint32_t num) +{ + int xfer_try = 0; + rt_ssize_t res = 0; + rt_bool_t clk_directly = RT_FALSE; + struct spacemit_i2c *i2c = raw_to_spacemit_i2c(bus); + + i2c->msgs = msgs; + i2c->num = num; + +_xfer_retry: + /* If unit keeps the last control status, don't need to do reset */ + if (spacemit_i2c_read(i2c, REG_CR) != i2c->i2c_ctrl_reg_value) + { + /* Controller & bus reset */ + spacemit_i2c_reset(i2c); + } + + /* Choose transfer mode */ + spacemit_i2c_choose_xfer_mode(i2c); + + /* Unit init */ + spacemit_i2c_unit_init(i2c); + + /* Clear all interrupt status */ + spacemit_i2c_clear_int_status(i2c, SPACEMIT_I2C_INT_STATUS_MASK); + + spacemit_i2c_init_xfer_params(i2c); + + res = spacemit_i2c_read(i2c, REG_RST_CYC); + spacemit_i2c_write(i2c, REG_RST_CYC, I2C_SDA_GLITCH_FIX_BYPASS | res); + + spacemit_i2c_mark_rw_flag(i2c); + + spacemit_i2c_enable(i2c); + + /* Wait for bus busy */ + if ((res = spacemit_i2c_recover_bus_busy(i2c))) + { + goto _err_recover; + } + + /* Msg transmit */ + if (i2c->xfer_mode == SPACEMIT_I2C_MODE_INTERRUPT) + { + res = spacemit_i2c_byte_xfer(i2c); + } + else if (i2c->xfer_mode == SPACEMIT_I2C_MODE_FIFO) + { + res = spacemit_i2c_fifo_xfer(i2c); + } + else + { + /* DMA */ + res = -RT_ENOSYS; + } + + if (res < 0) + { + if (res != -RT_ETIMEOUT) + { + res = -RT_EINVAL; + } + goto _err_xfer; + } + + if (i2c->xfer_mode == SPACEMIT_I2C_MODE_INTERRUPT) + { + if ((res = rt_completion_wait(&i2c->complete, i2c->timeout))) + { + spacemit_i2c_bus_reset(i2c); + spacemit_i2c_reset(i2c); + goto _timeout_xfex; + } + } + +_err_xfer: + if (!res) + { + spacemit_i2c_check_bus_release(i2c); + } + +_err_recover: +_timeout_xfex: + /* Disable spacemit i2c */ + spacemit_i2c_disable(i2c); + + /* Process i2c error */ + if (i2c->i2c_err) + { + if (i2c->i2c_err & (SR_BED | SR_ALD)) + { + spacemit_i2c_reset(i2c); + } + + /* Try transfer again */ + if (i2c->i2c_err & (SR_RXOV | SR_ALD)) + { + spacemit_i2c_flush_fifo_buffer(i2c); + } + + res = -RT_EIO; + } + + xfer_try++; + /* Retry i2c transfer 3 times for timeout and bus busy */ + if ((res == -RT_ETIMEOUT || res == -RT_EIO) && xfer_try <= i2c->drv_retries) + { + rt_hw_us_delay(175); + res = 0; + goto _xfer_retry; + } + + if (clk_directly) + { + /* If clock is enabled directly, here disable it */ + rt_clk_disable(i2c->clk); + } + + return res < 0 ? res : num; +} + +const static struct rt_i2c_bus_device_ops spacemit_i2c_ops = +{ + .master_xfer = spacemit_i2c_xfer, +}; + +static void spacemit_i2c_isr(int irq, void *param) +{ + rt_ssize_t res = 0; + rt_uint32_t status, ctrl; + struct spacemit_i2c *i2c = param; + + /* Record i2c status */ + status = spacemit_i2c_read(i2c, REG_SR); + i2c->i2c_status = status; + + /* Check if a valid interrupt status */ + if (!status) + { + return; + } + + /* Bus error, rx overrun, arbitration lost */ + i2c->i2c_err = status & (SR_BED | SR_RXOV | SR_ALD); + + /* Clear interrupt status bits[31:18]*/ + spacemit_i2c_clear_int_status(i2c, status); + + /* Error happens */ + if (i2c->i2c_err) + { + goto _err_out; + } + + /* Process interrupt mode */ + if (i2c->xfer_mode == SPACEMIT_I2C_MODE_INTERRUPT) + { + res = spacemit_i2c_byte_xfer(i2c); + } + +_err_out: + /* Send transaction complete signal: error happens, detect master stop */ + if (i2c->i2c_err || res < 0 || (status & SR_MSD)) + { + /* + * Here the transaction is already done, we don't need any + * other interrupt signals from now, in case any interrupt + * happens before spacemit_i2c_xfer to disable irq and i2c unit, + * we mask all the interrupt signals and clear the interrupt status. + */ + ctrl = spacemit_i2c_read(i2c, REG_CR); + ctrl &= ~SPACEMIT_I2C_INT_CTRL_MASK; + spacemit_i2c_write(i2c, REG_CR, ctrl); + + spacemit_i2c_clear_int_status(i2c, SPACEMIT_I2C_INT_STATUS_MASK); + + rt_completion_done(&i2c->complete); + } +} + +static void spacemit_i2c_free(struct spacemit_i2c *i2c, struct rt_device *dev) +{ + if (i2c->regs) + { + rt_iounmap(i2c->regs); + } + + if (!rt_is_err_or_null(i2c->rstc)) + { + rt_reset_control_assert(i2c->rstc); + rt_reset_control_put(i2c->rstc); + } + + if (!rt_is_err_or_null(i2c->clk)) + { + rt_clk_disable_unprepare(i2c->clk); + rt_clk_put(i2c->clk); + } + + rt_free(i2c); +} + +static rt_err_t spacemit_i2c_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + const char *dev_name; + struct rt_device *dev = &pdev->parent; + struct spacemit_i2c *i2c = rt_calloc(1, sizeof(*i2c)); + + if (!i2c) + { + return -RT_ENOMEM; + } + + i2c->regs = rt_dm_dev_iomap(dev, 0); + if (!i2c->regs) + { + err = -RT_EIO; + goto _fail; + } + + i2c->irq = rt_dm_dev_get_irq(dev, 0); + if (i2c->irq < 0) + { + err = i2c->irq; + goto _fail; + } + + i2c->rstc = rt_reset_control_get_by_index(dev, 0); + if (rt_is_err(i2c->rstc)) + { + goto _fail; + } + + /* Reset the i2c controller */ + rt_reset_control_assert(i2c->rstc); + rt_hw_us_delay(200); + rt_reset_control_deassert(i2c->rstc); + + /* Enable fast speed mode */ + i2c->fast_mode = rt_dm_dev_prop_read_bool(dev, "spacemit,i2c-fast-mode"); + /* Enable high speed mode */ + i2c->high_mode = rt_dm_dev_prop_read_bool(dev, "spacemit,i2c-high-mode"); + + if (i2c->high_mode) + { + /* Get master code for high speed mode */ + if (rt_dm_dev_prop_read_u8(dev, "spacemit,i2c-master-code", &i2c->master_code)) + { + i2c->master_code = 0x0e; + LOG_W("Failed to get i2c master code, use default: %#x", i2c->master_code); + } + } + + if ((err = rt_dm_dev_prop_read_u32(dev, "spacemit,i2c-clk-rate", &i2c->clk_rate))) + { + goto _fail; + } + + if ((err = rt_dm_dev_prop_read_u32(dev, "spacemit,i2c-lcr", &i2c->i2c_lcr))) + { + goto _fail; + } + + if ((err = rt_dm_dev_prop_read_u32(dev, "spacemit,i2c-wcr", &i2c->i2c_wcr))) + { + goto _fail; + } + + if ((err = rt_dm_dev_prop_read_u32(dev, "spacemit,adapter-id", (rt_uint32_t *)&pdev->dev_id))) + { + pdev->dev_id = -1; + } + + /* Disable DMA transfer mode, default: interrupt mode */ + i2c->dma_disable = RT_TRUE; + i2c->xfer_mode = i2c->dma_disable ? SPACEMIT_I2C_MODE_INTERRUPT : SPACEMIT_I2C_MODE_DMA; + + i2c->drv_retries = 3; + + /* The clock will always on and not use runtime mechanism */ + i2c->clk_always_on = rt_dm_dev_prop_read_bool(dev, "spacemit,clk-always-on"); + + /* APB clock: 26MHz or 52MHz */ + if ((err = rt_dm_dev_prop_read_u32(dev, "spacemit,apb_clock", &i2c->apb_clock))) + { + goto _fail; + } + else if (i2c->apb_clock != SPACEMIT_I2C_APB_CLOCK_26M && + i2c->apb_clock != SPACEMIT_I2C_APB_CLOCK_52M) + { + err = -RT_EINVAL; + goto _fail; + } + + i2c->clk = rt_clk_get_by_index(dev, 0); + if (rt_is_err(i2c->clk)) + { + err = rt_ptr_err(i2c->clk); + goto _fail; + } + rt_clk_prepare_enable(i2c->clk); + + rt_completion_init(&i2c->complete); + rt_spin_lock_init(&i2c->fifo_lock); + + if (pdev->dev_id >= 0) + { + rt_dm_dev_set_name(&i2c->parent.parent, "i2c%d", pdev->dev_id); + } + else + { + rt_dm_dev_set_name_auto(&i2c->parent.parent, "i2c"); + } + dev_name = rt_dm_dev_get_name(&i2c->parent.parent); + + rt_hw_interrupt_install(i2c->irq, spacemit_i2c_isr, i2c, dev_name); + rt_hw_interrupt_umask(i2c->irq); + + dev->user_data = i2c; + + i2c->parent.ops = &spacemit_i2c_ops; + i2c->parent.parent.ofw_node = dev->ofw_node; + + if ((err = rt_i2c_bus_device_register(&i2c->parent, dev_name))) + { + goto _free_irq; + } + + rt_dm_dev_bind_fwdata(dev, RT_NULL, i2c); + + return RT_EOK; + +_free_irq: + rt_hw_interrupt_mask(i2c->irq); + rt_pic_detach_irq(i2c->irq, i2c); + +_fail: + spacemit_i2c_free(i2c, dev); + + return err; +} + +static rt_err_t spacemit_i2c_remove(struct rt_platform_device *pdev) +{ + struct rt_device *dev = &pdev->parent; + struct spacemit_i2c *i2c = dev->user_data; + + rt_hw_interrupt_mask(i2c->irq); + rt_pic_detach_irq(i2c->irq, i2c); + + rt_device_unregister(&i2c->parent.parent); + + spacemit_i2c_free(i2c, dev); + + return RT_EOK; +} + +static const struct rt_ofw_node_id spacemit_i2c_ofw_ids[] = +{ + { .compatible = "spacemit,k1x-i2c" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_i2c_driver = +{ + .name = "spacemit-k1x-i2c", + .ids = spacemit_i2c_ofw_ids, + + .probe = spacemit_i2c_probe, + .remove = spacemit_i2c_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(spacemit_i2c_driver); diff --git a/bsp/spacemit/dm/include/dt-bindings/clock/k1x.h b/bsp/spacemit/dm/include/dt-bindings/clock/k1x.h new file mode 100644 index 000000000000..9e2a5e0f8000 --- /dev/null +++ b/bsp/spacemit/dm/include/dt-bindings/clock/k1x.h @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2006-2025, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __DT_BINDINGS_CLOCK_K1X_H__ +#define __DT_BINDINGS_CLOCK_K1X_H__ + +#define CLK_PLL2 0 +#define CLK_PLL3 1 +#define CLK_PLL1_D2 2 +#define CLK_PLL1_D3 3 +#define CLK_PLL1_D4 4 +#define CLK_PLL1_D5 5 +#define CLK_PLL1_D6 6 +#define CLK_PLL1_D7 7 +#define CLK_PLL1_D8 8 +#define CLK_PLL1_D11 9 +#define CLK_PLL1_D13 10 +#define CLK_PLL1_D23 11 +#define CLK_PLL1_D64 12 +#define CLK_PLL1_D10_AUD 13 +#define CLK_PLL1_D100_AUD 14 +#define CLK_PLL2_D1 15 +#define CLK_PLL2_D2 16 +#define CLK_PLL2_D3 17 +#define CLK_PLL2_D4 18 +#define CLK_PLL2_D5 19 +#define CLK_PLL2_D6 20 +#define CLK_PLL2_D7 21 +#define CLK_PLL2_D8 22 +#define CLK_PLL3_D1 23 +#define CLK_PLL3_D2 24 +#define CLK_PLL3_D3 25 +#define CLK_PLL3_D4 26 +#define CLK_PLL3_D5 27 +#define CLK_PLL3_D6 28 +#define CLK_PLL3_D7 29 +#define CLK_PLL3_D8 30 +#define CLK_PLL1_307P2 31 +#define CLK_PLL1_76P8 32 +#define CLK_PLL1_61P44 33 +#define CLK_PLL1_153P6 34 +#define CLK_PLL1_102P4 35 +#define CLK_PLL1_51P2 36 +#define CLK_PLL1_51P2_AP 37 +#define CLK_PLL1_57P6 38 +#define CLK_PLL1_25P6 39 +#define CLK_PLL1_12P8 40 +#define CLK_PLL1_12P8_WDT 41 +#define CLK_PLL1_6P4 42 +#define CLK_PLL1_3P2 43 +#define CLK_PLL1_1P6 44 +#define CLK_PLL1_0P8 45 +#define CLK_PLL1_351 46 +#define CLK_PLL1_409P6 47 +#define CLK_PLL1_204P8 48 +#define CLK_PLL1_491 49 +#define CLK_PLL1_245P76 50 +#define CLK_PLL1_614 51 +#define CLK_PLL1_47P26 52 +#define CLK_PLL1_31P5 53 +#define CLK_PLL1_819 54 +#define CLK_PLL1_1228 55 +#define CLK_SLOW_UART1 56 +#define CLK_SLOW_UART2 57 +#define CLK_UART1 58 +#define CLK_UART2 59 +#define CLK_UART3 60 +#define CLK_UART4 61 +#define CLK_UART5 62 +#define CLK_UART6 63 +#define CLK_UART7 64 +#define CLK_UART8 65 +#define CLK_UART9 66 +#define CLK_GPIO 67 +#define CLK_PWM0 68 +#define CLK_PWM1 69 +#define CLK_PWM2 70 +#define CLK_PWM3 71 +#define CLK_PWM4 72 +#define CLK_PWM5 73 +#define CLK_PWM6 74 +#define CLK_PWM7 75 +#define CLK_PWM8 76 +#define CLK_PWM9 77 +#define CLK_PWM10 78 +#define CLK_PWM11 79 +#define CLK_PWM12 80 +#define CLK_PWM13 81 +#define CLK_PWM14 82 +#define CLK_PWM15 83 +#define CLK_PWM16 84 +#define CLK_PWM17 85 +#define CLK_PWM18 86 +#define CLK_PWM19 87 +#define CLK_SSP3 88 +#define CLK_RTC 89 +#define CLK_TWSI0 90 +#define CLK_TWSI1 91 +#define CLK_TWSI2 92 +#define CLK_TWSI4 93 +#define CLK_TWSI5 94 +#define CLK_TWSI6 95 +#define CLK_TWSI7 96 +#define CLK_TWSI8 97 +#define CLK_TIMERS1 98 +#define CLK_TIMERS2 99 +#define CLK_AIB 100 +#define CLK_ONEWIRE 101 +#define CLK_SSPA0 102 +#define CLK_SSPA1 103 +#define CLK_DRO 104 +#define CLK_IR 105 +#define CLK_TSEN 106 +#define CLK_IPC_AP2AUD 107 +#define CLK_CAN0 108 +#define CLK_CAN0_BUS 109 +#define CLK_WDT 110 +#define CLK_RIPC 111 +#define CLK_JPG 112 +#define CLK_JPF_4KAFBC 113 +#define CLK_JPF_2KAFBC 114 +#define CLK_CCIC2PHY 115 +#define CLK_CCIC3PHY 116 +#define CLK_CSI 117 +#define CLK_CAMM0 118 +#define CLK_CAMM1 119 +#define CLK_CAMM2 120 +#define CLK_ISP_CPP 121 +#define CLK_ISP_BUS 122 +#define CLK_ISP 123 +#define CLK_DPU_MCLK 124 +#define CLK_DPU_ESC 125 +#define CLK_DPU_BIT 126 +#define CLK_DPU_PXCLK 127 +#define CLK_DPU_HCLK 128 +#define CLK_DPU_SPI 129 +#define CLK_DPU_SPI_HBUS 130 +#define CLK_DPU_SPIBUS 131 +#define CLK_SPU_SPI_ACLK 132 +#define CLK_V2D 133 +#define CLK_CCIC_4X 134 +#define CLK_CCIC1PHY 135 +#define CLK_SDH_AXI 136 +#define CLK_SDH0 137 +#define CLK_SDH1 138 +#define CLK_SDH2 139 +#define CLK_USB_P1 140 +#define CLK_USB_AXI 141 +#define CLK_USB30 142 +#define CLK_QSPI 143 +#define CLK_QSPI_BUS 144 +#define CLK_DMA 145 +#define CLK_AES 146 +#define CLK_VPU 147 +#define CLK_GPU 148 +#define CLK_EMMC 149 +#define CLK_EMMC_X 150 +#define CLK_AUDIO 151 +#define CLK_HDMI 152 +#define CLK_CCI550 153 +#define CLK_PMUA_ACLK 154 +#define CLK_CPU_C0_HI 155 +#define CLK_CPU_C0_CORE 156 +#define CLK_CPU_C0_ACE 157 +#define CLK_CPU_C0_TCM 158 +#define CLK_CPU_C1_HI 159 +#define CLK_CPU_C1_CORE 160 +#define CLK_CPU_C1_ACE 161 +#define CLK_PCIE0 162 +#define CLK_PCIE1 163 +#define CLK_PCIE2 164 +#define CLK_EMAC0_BUS 165 +#define CLK_EMAC0_PTP 166 +#define CLK_EMAC1_BUS 167 +#define CLK_EMAC1_PTP 168 + +#define CLK_SEC_UART1 169 +#define CLK_SEC_SSP2 170 +#define CLK_SEC_TWSI3 171 +#define CLK_SEC_RTC 172 +#define CLK_SEC_TIMERS0 173 +#define CLK_SEC_KPC 174 +#define CLK_SEC_GPIO 175 + +#define CLK_APB 176 + +#define CLK_PLL3_80 177 +#define CLK_PLL3_40 178 +#define CLK_PLL3_20 179 + +#define CLK_SLOW_UART 180 + +#define CLK_I2S_SYSCLK 181 +#define CLK_I2S_BCLK 182 +#define CLK_RCPU_HDMIAUDIO 183 +#define CLK_RCPU_CAN 184 +#define CLK_RCPU_CAN_BUS 185 + +#define CLK_RCPU_I2C0 186 +#define CLK_RCPU_SSP0 187 +#define CLK_RCPU_IR 188 +#define CLK_RCPU_UART0 189 +#define CLK_RCPU_UART1 190 + +#define CLK_DPLL1 191 +#define CLK_DPLL2 192 + +#define CLK_DFC_LVL0 193 +#define CLK_DFC_LVL1 194 +#define CLK_DFC_LVL2 195 +#define CLK_DFC_LVL3 196 +#define CLK_DFC_LVL4 197 +#define CLK_DFC_LVL5 198 +#define CLK_DFC_LVL6 199 +#define CLK_DFC_LVL7 200 +#define CLK_DDR 201 + +#define CLK_RCPU2_PWM0 202 +#define CLK_RCPU2_PWM1 203 +#define CLK_RCPU2_PWM2 204 +#define CLK_RCPU2_PWM3 205 +#define CLK_RCPU2_PWM4 206 +#define CLK_RCPU2_PWM5 207 +#define CLK_RCPU2_PWM6 208 +#define CLK_RCPU2_PWM7 209 +#define CLK_RCPU2_PWM8 210 +#define CLK_RCPU2_PWM9 211 + +#define CLK_AUDIO_APB 212 +#define CLK_AUDIO_AXI 213 + +#define CLK_PM_MN_SRC 214 +#define CLK_PM_MN 215 +#define CLK_PM_MN2_SRC 216 +#define CLK_PM_MN2 217 + +#define CLK_MAX_NO 218 + +#endif /* __DT_BINDINGS_CLOCK_K1X_H__ */ diff --git a/bsp/spacemit/dm/include/dt-bindings/pinctrl/k1x.h b/bsp/spacemit/dm/include/dt-bindings/pinctrl/k1x.h new file mode 100644 index 000000000000..101fcba595d7 --- /dev/null +++ b/bsp/spacemit/dm/include/dt-bindings/pinctrl/k1x.h @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2006-2025, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __DT_BINDINGS_PINCTRL_K1X_H__ +#define __DT_BINDINGS_PINCTRL_K1X_H__ + +/* Pin offset */ +#define PINID(x) ((x) + 1) + +#define GPIO_00 PINID(0) +#define GPIO_01 PINID(1) +#define GPIO_02 PINID(2) +#define GPIO_03 PINID(3) +#define GPIO_04 PINID(4) +#define GPIO_05 PINID(5) +#define GPIO_06 PINID(6) +#define GPIO_07 PINID(7) +#define GPIO_08 PINID(8) +#define GPIO_09 PINID(9) +#define GPIO_10 PINID(10) +#define GPIO_11 PINID(11) +#define GPIO_12 PINID(12) +#define GPIO_13 PINID(13) +#define GPIO_14 PINID(14) +#define GPIO_15 PINID(15) +#define GPIO_16 PINID(16) +#define GPIO_17 PINID(17) +#define GPIO_18 PINID(18) +#define GPIO_19 PINID(19) +#define GPIO_20 PINID(20) +#define GPIO_21 PINID(21) +#define GPIO_22 PINID(22) +#define GPIO_23 PINID(23) +#define GPIO_24 PINID(24) +#define GPIO_25 PINID(25) +#define GPIO_26 PINID(26) +#define GPIO_27 PINID(27) +#define GPIO_28 PINID(28) +#define GPIO_29 PINID(29) +#define GPIO_30 PINID(30) +#define GPIO_31 PINID(31) + +#define GPIO_32 PINID(32) +#define GPIO_33 PINID(33) +#define GPIO_34 PINID(34) +#define GPIO_35 PINID(35) +#define GPIO_36 PINID(36) +#define GPIO_37 PINID(37) +#define GPIO_38 PINID(38) +#define GPIO_39 PINID(39) +#define GPIO_40 PINID(40) +#define GPIO_41 PINID(41) +#define GPIO_42 PINID(42) +#define GPIO_43 PINID(43) +#define GPIO_44 PINID(44) +#define GPIO_45 PINID(45) +#define GPIO_46 PINID(46) +#define GPIO_47 PINID(47) +#define GPIO_48 PINID(48) +#define GPIO_49 PINID(49) +#define GPIO_50 PINID(50) +#define GPIO_51 PINID(51) +#define GPIO_52 PINID(52) +#define GPIO_53 PINID(53) +#define GPIO_54 PINID(54) +#define GPIO_55 PINID(55) +#define GPIO_56 PINID(56) +#define GPIO_57 PINID(57) +#define GPIO_58 PINID(58) +#define GPIO_59 PINID(59) +#define GPIO_60 PINID(60) +#define GPIO_61 PINID(61) +#define GPIO_62 PINID(62) +#define GPIO_63 PINID(63) + +#define GPIO_64 PINID(64) +#define GPIO_65 PINID(65) +#define GPIO_66 PINID(66) +#define GPIO_67 PINID(67) +#define GPIO_68 PINID(68) +#define GPIO_69 PINID(69) +#define PRI_TDI PINID(70) +#define PRI_TMS PINID(71) +#define PRI_TCK PINID(72) +#define PRI_TDO PINID(73) +#define GPIO_74 PINID(74) +#define GPIO_75 PINID(75) +#define GPIO_76 PINID(76) +#define GPIO_77 PINID(77) +#define GPIO_78 PINID(78) +#define GPIO_79 PINID(79) +#define GPIO_80 PINID(80) +#define GPIO_81 PINID(81) +#define GPIO_82 PINID(82) +#define GPIO_83 PINID(83) +#define GPIO_84 PINID(84) +#define GPIO_85 PINID(85) + +#define QSPI_DAT0 PINID(89) +#define QSPI_DAT1 PINID(90) +#define QSPI_DAT2 PINID(91) +#define QSPI_DAT3 PINID(92) +#define QSPI_CSI PINID(93) +#define QSPI_CLK PINID(94) + +#define MMC1_DAT3 PINID(109) +#define MMC1_DAT2 PINID(110) +#define MMC1_DAT1 PINID(111) +#define MMC1_DAT0 PINID(112) +#define MMC1_CMD PINID(113) +#define MMC1_CLK PINID(114) +#define GPIO_110 PINID(115) +#define PWR_SCL PINID(116) +#define PWR_SDA PINID(117) +#define VCXO_EN PINID(118) +#define DVL0 PINID(119) +#define DVL1 PINID(120) +#define PMIC_INT_N PINID(121) +#define GPIO_86 PINID(122) +#define GPIO_87 PINID(123) +#define GPIO_88 PINID(124) +#define GPIO_89 PINID(125) +#define GPIO_90 PINID(126) +#define GPIO_91 PINID(127) +#define GPIO_92 PINID(128) + +#define GPIO_111 PINID(130) +#define GPIO_112 PINID(131) +#define GPIO_113 PINID(132) +#define GPIO_114 PINID(133) +#define GPIO_115 PINID(134) +#define GPIO_116 PINID(135) +#define GPIO_117 PINID(136) +#define GPIO_118 PINID(137) +#define GPIO_119 PINID(138) +#define GPIO_120 PINID(139) +#define GPIO_121 PINID(140) +#define GPIO_122 PINID(141) +#define GPIO_123 PINID(142) +#define GPIO_124 PINID(143) +#define GPIO_125 PINID(144) +#define GPIO_126 PINID(145) +#define GPIO_127 PINID(146) + +#define EMMC_D0 PINID(147) +#define EMMC_D1 PINID(148) +#define EMMC_D2 PINID(149) +#define EMMC_D3 PINID(150) +#define EMMC_D4 PINID(151) +#define EMMC_D5 PINID(152) +#define EMMC_D6 PINID(153) +#define EMMC_D7 PINID(154) +#define EMMC_DS PINID(155) +#define EMMC_CLK PINID(156) +#define EMMC_CMD PINID(157) + +/* Pin mux */ +#define MUX_MODE0 0 +#define MUX_MODE1 1 +#define MUX_MODE2 2 +#define MUX_MODE3 3 +#define MUX_MODE4 4 +#define MUX_MODE5 5 +#define MUX_MODE6 6 +#define MUX_MODE7 7 + +/* Strong pull resistor */ +#define SPU_EN (1 << 3) + +/* Edge detect */ +#define EDGE_NONE (1 << 6) +#define EDGE_RISE (1 << 4) +#define EDGE_FALL (1 << 5) +#define EDGE_BOTH (3 << 4) + +/* Slew rate output control */ +#define SLE_EN (1 << 7) + +/* Schmitter trigger input threshhold */ +#define ST00 (0 << 8) +#define ST01 (1 << 8) +#define ST02 (2 << 8) +#define ST03 (3 << 8) + +/* Driver strength*/ +#define PAD_1V8_DS0 (0 << 11) +#define PAD_1V8_DS1 (1 << 11) +#define PAD_1V8_DS2 (2 << 11) +#define PAD_1V8_DS3 (3 << 11) + +/* Ds2 ---> bit10, ds1 ----> bit12, ds0 ----> bit11 */ +#define PAD_3V_DS0 (0 << 10) /* bit[12:10] 000 */ +#define PAD_3V_DS1 (2 << 10) /* bit[12:10] 010 */ +#define PAD_3V_DS2 (4 << 10) /* bit[12:10] 100 */ +#define PAD_3V_DS3 (6 << 10) /* bit[12:10] 110 */ +#define PAD_3V_DS4 (1 << 10) /* bit[12:10] 001 */ +#define PAD_3V_DS5 (3 << 10) /* bit[12:10] 011 */ +#define PAD_3V_DS6 (5 << 10) /* bit[12:10] 101 */ +#define PAD_3V_DS7 (7 << 10) /* bit[12:10] 111 */ + +/* Pull up/down */ +#define PULL_DIS (0 << 13) /* bit[15:13] 000 */ +#define PULL_UP (6 << 13) /* bit[15:13] 110 */ +#define PULL_DOWN (5 << 13) /* bit[15:13] 101 */ + +#define K1X_PADCONF(pinid, conf, mux) ((pinid) * 4) (conf) (mux) + +#endif /* __DT_BINDINGS_PINCTRL_K1X_H__ */ diff --git a/bsp/spacemit/dm/include/dt-bindings/power/k1x_pmu.h b/bsp/spacemit/dm/include/dt-bindings/power/k1x_pmu.h new file mode 100644 index 000000000000..7281265d26cf --- /dev/null +++ b/bsp/spacemit/dm/include/dt-bindings/power/k1x_pmu.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2006-2025, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __DT_BINDINGS_POWER_K1X_PMU_H__ +#define __DT_BINDINGS_POWER_K1X_PMU_H__ + +#define K1X_PMU_BUS_PWR_DOMAIN 0 +#define K1X_PMU_VPU_PWR_DOMAIN 1 +#define K1X_PMU_GPU_PWR_DOMAIN 2 +#define K1X_PMU_LCD_PWR_DOMAIN 3 +#define K1X_PMU_ISP_PWR_DOMAIN 4 +#define K1X_PMU_AUD_PWR_DOMAIN 5 +#define K1X_PMU_GNSS_PWR_DOMAIN 6 +#define K1X_PMU_HDMI_PWR_DOMAIN 7 +#define K1X_PMU_DUMMY_PWR_DOMAIN 8 + +#endif /* __DT_BINDINGS_POWER_K1X_PMU_H__ */ diff --git a/bsp/spacemit/dm/include/dt-bindings/reset/k1x.h b/bsp/spacemit/dm/include/dt-bindings/reset/k1x.h new file mode 100644 index 000000000000..5c9164a4a5a9 --- /dev/null +++ b/bsp/spacemit/dm/include/dt-bindings/reset/k1x.h @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2006-2025, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __DT_BINDINGS_RESET_K1X_H__ +#define __DT_BINDINGS_RESET_K1X_H__ + +/* APBC */ +#define RESET_UART1 1 +#define RESET_UART2 2 +#define RESET_GPIO 3 +#define RESET_PWM0 4 +#define RESET_PWM1 5 +#define RESET_PWM2 6 +#define RESET_PWM3 7 +#define RESET_PWM4 8 +#define RESET_PWM5 9 +#define RESET_PWM6 10 +#define RESET_PWM7 11 +#define RESET_PWM8 12 +#define RESET_PWM9 13 +#define RESET_PWM10 14 +#define RESET_PWM11 15 +#define RESET_PWM12 16 +#define RESET_PWM13 17 +#define RESET_PWM14 18 +#define RESET_PWM15 19 +#define RESET_PWM16 20 +#define RESET_PWM17 21 +#define RESET_PWM18 22 +#define RESET_PWM19 23 +#define RESET_SSP3 24 +#define RESET_UART3 25 +#define RESET_RTC 26 +#define RESET_TWSI0 27 + +#define RESET_TIMERS1 28 +#define RESET_AIB 29 +#define RESET_TIMERS2 30 +#define RESET_ONEWIRE 31 +#define RESET_SSPA0 32 +#define RESET_SSPA1 33 +#define RESET_DRO 34 +#define RESET_IR 35 +#define RESET_TWSI1 36 + +#define RESET_TSEN 37 +#define RESET_TWSI2 38 +#define RESET_TWSI4 39 +#define RESET_TWSI5 40 +#define RESET_TWSI6 41 +#define RESET_TWSI7 42 +#define RESET_TWSI8 43 +#define RESET_IPC_AP2AUD 44 +#define RESET_UART4 45 +#define RESET_UART5 46 +#define RESET_UART6 47 +#define RESET_UART7 48 +#define RESET_UART8 49 +#define RESET_UART9 50 +#define RESET_CAN0 51 + +/* MPMU */ +#define RESET_WDT 52 + +/* APMU */ +#define RESET_JPG 53 +#define RESET_CSI 54 +#define RESET_CCIC2_PHY 55 +#define RESET_CCIC3_PHY 56 +#define RESET_ISP 57 +#define RESET_ISP_AHB 58 +#define RESET_ISP_CI 59 +#define RESET_ISP_CPP 60 +#define RESET_LCD 61 +#define RESET_DSI_ESC 62 +#define RESET_V2D 63 +#define RESET_MIPI 64 +#define RESET_LCD_SPI 65 +#define RESET_LCD_SPI_BUS 66 +#define RESET_LCD_SPI_HBUS 67 +#define RESET_LCD_MCLK 68 +#define RESET_CCIC_4X 69 +#define RESET_CCIC1_PHY 70 +#define RESET_SDH_AXI 71 +#define RESET_SDH0 72 +#define RESET_SDH1 73 +#define RESET_USB_AXI 74 +#define RESET_USBP1_AXI 75 +#define RESET_USB3_0 76 +#define RESET_QSPI 77 +#define RESET_QSPI_BUS 78 +#define RESET_DMA 79 +#define RESET_AES 80 +#define RESET_VPU 81 +#define RESET_GPU 82 +#define RESET_SDH2 83 +#define RESET_MC 84 +#define RESET_EM_AXI 85 +#define RESET_EM 86 +#define RESET_AUDIO_SYS 87 +#define RESET_HDMI 88 +#define RESET_PCIE0 89 +#define RESET_PCIE1 90 +#define RESET_PCIE2 91 +#define RESET_EMAC0 92 +#define RESET_EMAC1 93 + +/* APBC2 */ +#define RESET_SEC_UART1 94 +#define RESET_SEC_SSP2 95 +#define RESET_SEC_TWSI3 96 +#define RESET_SEC_RTC 97 +#define RESET_SEC_TIMERS0 98 +#define RESET_SEC_KPC 99 +#define RESET_SEC_GPIO 100 + +#define RESET_RCPU_HDMIAUDIO 101 +#define RESET_RCPU_CAN 102 + +#define RESET_RCPU_I2C0 103 +#define RESET_RCPU_SSP0 104 +#define RESET_RCPU_IR 105 +#define RESET_RCPU_UART0 106 +#define RESET_RCPU_UART1 107 + +#define RESET_RCPU2_PWM0 108 +#define RESET_RCPU2_PWM1 109 +#define RESET_RCPU2_PWM2 110 +#define RESET_RCPU2_PWM3 111 +#define RESET_RCPU2_PWM4 112 +#define RESET_RCPU2_PWM5 113 +#define RESET_RCPU2_PWM6 114 +#define RESET_RCPU2_PWM7 115 +#define RESET_RCPU2_PWM8 116 +#define RESET_RCPU2_PWM9 117 + +#define RESET_NUMBER 118 + +#endif /* __DT_BINDINGS_RESET_K1X_H__ */ diff --git a/bsp/spacemit/dm/include/firmware-spacemit.h b/bsp/spacemit/dm/include/firmware-spacemit.h new file mode 100644 index 000000000000..54379e1211fd --- /dev/null +++ b/bsp/spacemit/dm/include/firmware-spacemit.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __FIRMWARE_SPACEMIT_H__ +#define __FIRMWARE_SPACEMIT_H__ + +#ifdef __ASSEMBLY__ +#include + +.macro SPACEMIT_FIRMWARE_DEFINE name + .align RISCV_SZPTR +firmware_\name: + .ascii "\name" "\0" +firmware_\name\()_start: + .incbin "\name" +firmware_\name\()_end: +.endm + +.macro SPACEMIT_FIRMWARE_REF name + RISCV_PTR firmware_\name + RISCV_PTR firmware_\name\()_start + RISCV_PTR firmware_\name\()_end +.endm + +.macro SPACEMIT_FIRMWARE_START + .align RISCV_SZPTR + .globl spacemit_firmwares_start +spacemit_firmwares_start: +.endm + +.macro SPACEMIT_FIRMWARE_END + .globl spacemit_firmwares_end +spacemit_firmwares_end: +.endm +#else +#include + +rt_bool_t spacemit_firmware_find(const char *name, rt_ubase_t *out_base, rt_size_t *out_size); +rt_err_t spacemit_firmware_load_elf(const char *name, rt_ubase_t phy_addr); + +#endif /* __ASSEMBLY__ */ + +#endif /* __FIRMWARE_SPACEMIT_H__ */ diff --git a/bsp/spacemit/dm/include/jpu.h b/bsp/spacemit/dm/include/jpu.h new file mode 100644 index 000000000000..fe648df5af42 --- /dev/null +++ b/bsp/spacemit/dm/include/jpu.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __JPU_H__ +#define __JPU_H__ + +#include +#include + +#define JPU_NAME "jpu" +#define JPU_BUFFER_MAX_SIZE (32U * 1024U * 1024U) +#define JPU_STREAM_PADDING 1024U + +#define JPU_HUFF_TABLE_NUM 4 +#define JPU_HUFF_BITS_NUM 16 +#define JPU_HUFF_VALUES_NUM 162 +#define JPU_QUANT_COMPONENT_NUM 3 +#define JPU_QUANT_VALUES_NUM 64 + +enum jpu_format +{ + JPU_FORMAT_420 = 0, + JPU_FORMAT_422, + JPU_FORMAT_440, + JPU_FORMAT_444, + JPU_FORMAT_400, +}; + +struct jpu_dec_tables +{ + uint8_t huff_bits[JPU_HUFF_TABLE_NUM][JPU_HUFF_BITS_NUM]; + uint8_t huff_values[JPU_HUFF_TABLE_NUM][JPU_HUFF_VALUES_NUM]; + uint16_t quant[JPU_QUANT_COMPONENT_NUM][JPU_QUANT_VALUES_NUM]; +}; + +struct jpu_buffer +{ + uint32_t size; + uint64_t phys_addr; + void *virt_addr; +}; + +/* + * width, height and format are inputs. The remaining fields are returned by + * JPU_QUERY_FRAME and describe the decoder's planar output buffer. + */ +struct jpu_frame_info +{ + uint16_t width; + uint16_t height; + uint8_t format; + uint8_t reserved[3]; + + uint16_t aligned_width; + uint16_t aligned_height; + uint16_t y_stride; + uint16_t c_stride; + uint16_t c_height; + uint16_t reserved2; + uint32_t size; +}; + +struct jpu_decode_request +{ + struct jpu_frame_info frame; + struct jpu_dec_tables tables; + + uint64_t stream_phys; + uint64_t frame_phys; + uint32_t stream_size; + uint32_t stream_capacity; + uint32_t frame_capacity; + uint32_t entropy_offset; + uint16_t restart_interval; + uint8_t components; + uint8_t dc_selector[3]; + uint8_t ac_selector[3]; + + uint32_t irq_status; + uint32_t picture_status; + uint32_t error_mcu; + uint32_t cycles; +}; + +#define JPU_IOC_MAGIC 'J' + +#define JPU_DECODE _IOWR(JPU_IOC_MAGIC, 0, struct jpu_decode_request) +#define JPU_QUERY_FRAME _IOWR(JPU_IOC_MAGIC, 1, struct jpu_frame_info) +#define JPU_ALLOC_BUFFER _IOWR(JPU_IOC_MAGIC, 2, struct jpu_buffer) +#define JPU_FREE_BUFFER _IOW(JPU_IOC_MAGIC, 3, struct jpu_buffer) +#define JPU_RESET _IO(JPU_IOC_MAGIC, 5) +#define JPU_GET_MMU_VERSION _IOR(JPU_IOC_MAGIC, 7, uint32_t) + +#endif /* __JPU_H__ */ diff --git a/bsp/spacemit/dm/include/k1-cru.h b/bsp/spacemit/dm/include/k1-cru.h new file mode 100644 index 000000000000..d53950633a2c --- /dev/null +++ b/bsp/spacemit/dm/include/k1-cru.h @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __K1_CLK_RST_H__ +#define __K1_CLK_RST_H__ + +#include +#include +#include + +/* APBS register offset */ +/* PLL1 */ +#define APB_SPARE1_REG 0x100 +#define APB_SPARE2_REG 0x104 +#define APB_SPARE3_REG 0x108 +/* PLL2 */ +#define APB_SPARE7_REG 0x118 +#define APB_SPARE8_REG 0x11c +#define APB_SPARE9_REG 0x120 +/* PLL3 */ +#define APB_SPARE10_REG 0x124 +#define APB_SPARE11_REG 0x128 +#define APB_SPARE12_REG 0x12c +/* end of APBS register offset */ + +/* APBC register offset */ +#define APBC_UART1_CLK_RST 0x0 +#define APBC_UART2_CLK_RST 0x4 +#define APBC_GPIO_CLK_RST 0x8 +#define APBC_PWM0_CLK_RST 0xc +#define APBC_PWM1_CLK_RST 0x10 +#define APBC_PWM2_CLK_RST 0x14 +#define APBC_PWM3_CLK_RST 0x18 +#define APBC_TWSI8_CLK_RST 0x20 +#define APBC_UART3_CLK_RST 0x24 +#define APBC_RTC_CLK_RST 0x28 +#define APBC_TWSI0_CLK_RST 0x2c +#define APBC_TWSI1_CLK_RST 0x30 +#define APBC_TIMERS1_CLK_RST 0x34 +#define APBC_TWSI2_CLK_RST 0x38 +#define APBC_AIB_CLK_RST 0x3c +#define APBC_TWSI4_CLK_RST 0x40 +#define APBC_TIMERS2_CLK_RST 0x44 +#define APBC_ONEWIRE_CLK_RST 0x48 +#define APBC_TWSI5_CLK_RST 0x4c +#define APBC_DRO_CLK_RST 0x58 +#define APBC_IR_CLK_RST 0x5c +#define APBC_TWSI6_CLK_RST 0x60 +#define APBC_COUNTER_CLK_SEL 0x64 +#define APBC_TWSI7_CLK_RST 0x68 +#define APBC_TSEN_CLK_RST 0x6c + +#define APBC_UART4_CLK_RST 0x70 +#define APBC_UART5_CLK_RST 0x74 +#define APBC_UART6_CLK_RST 0x78 +#define APBC_SSP3_CLK_RST 0x7c + +#define APBC_SSPA0_CLK_RST 0x80 +#define APBC_SSPA1_CLK_RST 0x84 + +#define APBC_IPC_AP2AUD_CLK_RST 0x90 +#define APBC_UART7_CLK_RST 0x94 +#define APBC_UART8_CLK_RST 0x98 +#define APBC_UART9_CLK_RST 0x9c + +#define APBC_CAN0_CLK_RST 0xa0 +#define APBC_PWM4_CLK_RST 0xa8 +#define APBC_PWM5_CLK_RST 0xac +#define APBC_PWM6_CLK_RST 0xb0 +#define APBC_PWM7_CLK_RST 0xb4 +#define APBC_PWM8_CLK_RST 0xb8 +#define APBC_PWM9_CLK_RST 0xbc +#define APBC_PWM10_CLK_RST 0xc0 +#define APBC_PWM11_CLK_RST 0xc4 +#define APBC_PWM12_CLK_RST 0xc8 +#define APBC_PWM13_CLK_RST 0xcc +#define APBC_PWM14_CLK_RST 0xd0 +#define APBC_PWM15_CLK_RST 0xd4 +#define APBC_PWM16_CLK_RST 0xd8 +#define APBC_PWM17_CLK_RST 0xdc +#define APBC_PWM18_CLK_RST 0xe0 +#define APBC_PWM19_CLK_RST 0xe4 +/* End of APBC register offset */ + +/* MPMU register offset */ +#define MPMU_POSR 0x10 +#define POSR_PLL1_LOCK RT_BIT(27) +#define POSR_PLL2_LOCK RT_BIT(28) +#define POSR_PLL3_LOCK RT_BIT(29) + +#define MPMU_VRCR 0x18 +#define MPMU_VRCR_REQ_EN0 RT_BIT(0) +#define MPMU_VRCR_REQ_EN2 RT_BIT(2) +#define MPMU_VRCR_REQ_POL2 RT_BIT(6) +#define MPMU_VRCR_VCXO_OUT_REQ_EN2 RT_BIT(14) + +#define MPMU_WDTPCR 0x200 +#define MPMU_RIPCCR 0x210 +#define MPMU_ACGR 0x1024 +#define MPMU_SUCCR 0x14 +#define MPMU_ISCCR 0x44 +#define MPMU_SUCCR_1 0x10b0 +#define MPMU_APBCSCR 0x1050 + +#define MPMU_PM_MN 0x10a4 +#define MPMU_PM_MN_GPCR2 0x48 +#define MPMU_PM_MN_GPCR 0x30 +/* End of MPMU register offset */ + +/* APMU register offset */ +#define APMU_JPG_CLK_RES_CTRL 0x20 +#define APMU_CSI_CCIC2_CLK_RES_CTRL 0x24 +#define APMU_ISP_CLK_RES_CTRL 0x38 +#define APMU_LCD_CLK_RES_CTRL1 0x44 +#define APMU_LCD_SPI_CLK_RES_CTRL 0x48 +#define APMU_LCD_CLK_RES_CTRL2 0x4c +#define APMU_CCIC_CLK_RES_CTRL 0x50 +#define APMU_SDH0_CLK_RES_CTRL 0x54 +#define APMU_SDH1_CLK_RES_CTRL 0x58 +#define APMU_USB_CLK_RES_CTRL 0x5c +#define APMU_QSPI_CLK_RES_CTRL 0x60 +#define APMU_USB_CLK_RES_CTRL 0x5c +#define APMU_DMA_CLK_RES_CTRL 0x64 +#define APMU_AES_CLK_RES_CTRL 0x68 +#define APMU_VPU_CLK_RES_CTRL 0xa4 +#define APMU_GPU_CLK_RES_CTRL 0xcc +#define APMU_SDH2_CLK_RES_CTRL 0xe0 +#define APMU_PMUA_MC_CTRL 0xe8 +#define APMU_PMU_CC2_AP 0x100 +#define APMU_PMUA_EM_CLK_RES_CTRL 0x104 + +#define APMU_AUDIO_CLK_RES_CTRL 0x14c +#define APMU_HDMI_CLK_RES_CTRL 0x1b8 +#define APMU_CCI550_CLK_CTRL 0x300 +#define APMU_ACLK_CLK_CTRL 0x388 +#define APMU_CPU_C0_CLK_CTRL 0x38c +#define APMU_CPU_C1_CLK_CTRL 0x390 + +#define APMU_PCIE_CLK_RES_CTRL_0 0x3cc +#define APMU_PCIE_CLK_RES_CTRL_1 0x3d4 +#define APMU_PCIE_CLK_RES_CTRL_2 0x3dc + +#define APMU_EMAC0_CLK_RES_CTRL 0x3e4 +#define APMU_EMAC1_CLK_RES_CTRL 0x3ec + +#define APMU_DFC_AP 0x180 +#define APMU_DFC_STATUS 0x188 + +#define APMU_DFC_LEVEL0 0x190 +#define APMU_DFC_LEVEL1 0x194 +#define APMU_DFC_LEVEL2 0x198 +#define APMU_DFC_LEVEL3 0x19c +#define APMU_DFC_LEVEL4 0x1a0 +#define APMU_DFC_LEVEL5 0x1a4 +#define APMU_DFC_LEVEL6 0x1a8 +#define APMU_DFC_LEVEL7 0x1ac + +#define APMU_DPLL1_CLK_CTRL1 0x39c +#define APMU_DPLL1_CLK_CTRL2 0x3a0 +#define APMU_DPLL2_CLK_CTRL1 0x3a8 +#define APMU_DPLL2_CLK_CTRL2 0x3ac +/* End of APMU register offset */ + +/* APBC2 register offset */ +#define APBC2_UART1_CLK_RST 0x00 +#define APBC2_SSP2_CLK_RST 0x04 +#define APBC2_TWSI3_CLK_RST 0x08 +#define APBC2_RTC_CLK_RST 0x0c +#define APBC2_TIMERS0_CLK_RST 0x10 +#define APBC2_KPC_CLK_RST 0x14 +#define APBC2_GPIO_CLK_RST 0x1c +/* End of APBC2 register offset */ + +/* RCPU register offset */ +#define RCPU_HDMI_CLK_RST 0x2044 +#define RCPU_CAN_CLK_RST 0x4c +#define RCPU_I2C0_CLK_RST 0x30 + +#define RCPU_SSP0_CLK_RST 0x28 +#define RCPU_IR_CLK_RST 0x48 +#define RCPU_UART0_CLK_RST 0xd8 +#define RCPU_UART1_CLK_RST 0x3c +/* End of RCPU register offset */ + +/* RCPU2 register offset */ +#define RCPU2_PWM0_CLK_RST 0x00 +#define RCPU2_PWM1_CLK_RST 0x04 +#define RCPU2_PWM2_CLK_RST 0x08 +#define RCPU2_PWM3_CLK_RST 0x0c +#define RCPU2_PWM4_CLK_RST 0x10 +#define RCPU2_PWM5_CLK_RST 0x14 +#define RCPU2_PWM6_CLK_RST 0x18 +#define RCPU2_PWM7_CLK_RST 0x1c +#define RCPU2_PWM8_CLK_RST 0x20 +#define RCPU2_PWM9_CLK_RST 0x24 +/* End of RCPU2 register offset */ + +/* AUDPMU register offset */ +#define AUDPMU_AUDIO_BUS_CLK_CTRL 0x38 +/* end of AUDPMU register offset */ + +enum cru_type +{ + CRU_BASE_TYPE_MPMU = 0, + CRU_BASE_TYPE_APMU, + CRU_BASE_TYPE_APBC, + CRU_BASE_TYPE_APBS, + CRU_BASE_TYPE_CIU, + CRU_BASE_TYPE_DCIU, + CRU_BASE_TYPE_DDRC, + CRU_BASE_TYPE_APBC2, + CRU_BASE_TYPE_RCPU, + CRU_BASE_TYPE_RCPU2, + CRU_BASE_TYPE_AUDPMU, + CRU_BASE_TYPE_AUDC, + CRU_BASE_TYPE_MAX, +}; + +#ifdef __CCU_H__ +RT_DEFINE_SPINLOCK(k1_cru_lock); +#else +extern struct rt_spinlock k1_cru_lock; +#endif + +#endif /* __K1_CLK_RST_H__ */ diff --git a/bsp/spacemit/dm/include/k1-tcm.h b/bsp/spacemit/dm/include/k1-tcm.h new file mode 100644 index 000000000000..6a135eed30a4 --- /dev/null +++ b/bsp/spacemit/dm/include/k1-tcm.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __K1_TCM_H__ +#define __K1_TCM_H__ + +#include +#include + +void *tcm_alloc_cpu(int cpuid, rt_size_t size); +void tcm_free_cpu(int cpuid, void *ptr); + +rt_inline void *tcm_alloc(rt_size_t size) +{ + return tcm_alloc_cpu(rt_hw_cpu_id(), size); +} + +rt_inline void tcm_free(void *ptr) +{ + return tcm_free_cpu(rt_hw_cpu_id(), ptr); +} + +#endif /* __K1_TCM_H__ */ diff --git a/bsp/spacemit/dm/include/k1x-rproc.h b/bsp/spacemit/dm/include/k1x-rproc.h new file mode 100644 index 000000000000..7f6acf87568b --- /dev/null +++ b/bsp/spacemit/dm/include/k1x-rproc.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __K1X_RPROC_H__ +#define __K1X_RPROC_H__ + +#include + +rt_err_t spacemit_k1x_rproc_boot(const char *fw_name); +void spacemit_k1x_rproc_dump_status(void); + +#endif /* __K1X_RPROC_H__ */ diff --git a/bsp/spacemit/dm/include/mfd/pm853.h b/bsp/spacemit/dm/include/mfd/pm853.h new file mode 100644 index 000000000000..8ab8d6919385 --- /dev/null +++ b/bsp/spacemit/dm/include/mfd/pm853.h @@ -0,0 +1,336 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __PM853_H__ +#define __PM853_H__ + +enum +{ + PM853_ID_DCDC1, + PM853_ID_DCDC2, + PM853_ID_DCDC3, + PM853_ID_DCDC4, + PM853_ID_DCDC5, + PM853_ID_LDO1, + PM853_ID_LDO2, + PM853_ID_LDO3, + PM853_ID_LDO4, + PM853_ID_LDO5, + PM853_ID_LDO6, + PM853_ID_LDO7, + PM853_ID_LDO8, + PM853_ID_LDO9, + PM853_ID_LDO10, + PM853_ID_LDO11, + PM853_ID_LDO12, + PM853_ID_LDO13, + PM853_ID_LDO14, + PM853_ID_LDO15, + PM853_ID_LDO16, + PM853_ID_LDO17, + PM853_ID_LDO18, + PM853_ID_LDO19, + PM853_ID_LDO20, + PM853_ID_LDO21, + PM853_ID_LDO22, + PM853_ID_LDO5_SW, +}; + +#define PM853_LDO_BUCK_EN_REG0 0x11 +#define PM853_LDO_BUCK_EN_REG1 0x12 +#define PM853_LDO_BUCK_EN_REG2 0x13 +#define PM853_LDO_BUCK_EN_REG3 0x14 + +#define PM853_BUCK1_EN_MSK 0x1 +#define PM853_BUCK2_EN_MSK 0x2 +#define PM853_BUCK3_EN_MSK 0x4 +#define PM853_BUCK4_EN_MSK 0x8 +#define PM853_BUCK5_EN_MSK 0x10 + +#define PM853_LDO1_EN_MSK 0x20 +#define PM853_LDO2_EN_MSK 0x40 +#define PM853_LDO3_EN_MSK 0x80 +#define PM853_LDO4_EN_MSK 0x1 +#define PM853_LDO5_EN_MSK 0x2 +#define PM853_LDO6_EN_MSK 0x4 +#define PM853_LDO7_EN_MSK 0x8 +#define PM853_LDO8_EN_MSK 0x10 +#define PM853_LDO9_EN_MSK 0x20 +#define PM853_LDO10_EN_MSK 0x40 +#define PM853_LDO11_EN_MSK 0x80 +#define PM853_LDO12_EN_MSK 0x1 +#define PM853_LDO13_EN_MSK 0x2 +#define PM853_LDO14_EN_MSK 0x4 +#define PM853_LDO15_EN_MSK 0x8 +#define PM853_LDO16_EN_MSK 0x10 +#define PM853_LDO17_EN_MSK 0x20 +#define PM853_LDO18_EN_MSK 0x40 +#define PM853_LDO19_EN_MSK 0x80 +#define PM853_LDO20_EN_MSK 0x1 +#define PM853_LDO21_EN_MSK 0x2 +#define PM853_LDO22_EN_MSK 0x4 +#define PM853_SW_EN_MSK 0x8 + + +#define PM853_BUCK1_VSEL_REG 0x30 +#define PM853_BUCK2_VSEL_REG 0x50 +#define PM853_BUCK3_VSEL_REG 0x60 +#define PM853_BUCK4_VSEL_REG 0x80 +#define PM853_BUCK5_VSEL_REG 0x90 + +#define PM853_BUCK1_VSEL_MSK 0x7f +#define PM853_BUCK2_VSEL_MSK 0x7f +#define PM853_BUCK3_VSEL_MSK 0x7f +#define PM853_BUCK4_VSEL_MSK 0x7f +#define PM853_BUCK5_VSEL_MSK 0x7f + +#define PM853_LDO_VSEL_MSK 0xf +#define PM853_LDO1_VSEL_REG 0xb1 +#define PM853_LDO2_VSEL_REG 0xb4 +#define PM853_LDO3_VSEL_REG 0xb7 +#define PM853_LDO4_VSEL_REG 0xba +#define PM853_LDO5_VSEL_REG 0xbd +#define PM853_LDO6_VSEL_REG 0xc0 +#define PM853_LDO7_VSEL_REG 0xc3 +#define PM853_LDO8_VSEL_REG 0xc6 +#define PM853_LDO9_VSEL_REG 0xc9 +#define PM853_LDO10_VSEL_REG 0xcc +#define PM853_LDO11_VSEL_REG 0xcf +#define PM853_LDO12_VSEL_REG 0xd2 +#define PM853_LDO13_VSEL_REG 0xd5 +#define PM853_LDO14_VSEL_REG 0xd8 +#define PM853_LDO15_VSEL_REG 0xdb +#define PM853_LDO16_VSEL_REG 0xde +#define PM853_LDO17_VSEL_REG 0xe1 +#define PM853_LDO18_VSEL_REG 0xe4 +#define PM853_LDO19_VSEL_REG 0xe7 +#define PM853_LDO20_VSEL_REG 0xea +#define PM853_LDO21_VSEL_REG 0xed +#define PM853_LDO22_VSEL_REG 0xf0 + +#define SPACEMIT_PM853_MAX_REG 0xf1 + +#define PM853_DESC(_id, _match, _supply, _nv, _vr, _vm, _er, _em, _lr) \ + SPACEMIT_PMIC_REGULATOR_DESC_COMMON(_id, _match, _supply, _nv, _vr, _vm, _er, _em, _lr, pmic_dcdc_ldo_ops) + +#define PM853_DESC_SWITCH(_id, _match, _supply, _ereg, _emask) \ + SPACEMIT_PMIC_REGULATOR_DESC_SWITCH_COM(_id, _match, _supply, _ereg, _emask, 0, 0, pmic_switch_ops) + +#ifdef __SPACEMIT_REGULATOR_INTERNAL +static const struct spacemit_pmic_regulator_range pm853_buck_ranges1[] = +{ + SPACEMIT_PMIC_REGULATOR_RANGE(480000, 0x0, 0x50, 10000), + SPACEMIT_PMIC_REGULATOR_RANGE(1320000, 0x51, 0x7F, 40000), +}; + +static const struct spacemit_pmic_regulator_range pm853_buck_ranges2[] = +{ + SPACEMIT_PMIC_REGULATOR_RANGE(600000, 0x0, 0x50, 12500), + SPACEMIT_PMIC_REGULATOR_RANGE(1650000, 0x51, 0x7F, 50000), +}; + +static const struct spacemit_pmic_regulator_range pm853_ldo_ranges1[] = +{ + SPACEMIT_PMIC_REGULATOR_RANGE(1200000, 0x0, 0x6, 100000), + SPACEMIT_PMIC_REGULATOR_RANGE(1850000, 0x7, 0x8, 50000), + SPACEMIT_PMIC_REGULATOR_RANGE(2750000, 0x9, 0xc, 50000), + SPACEMIT_PMIC_REGULATOR_RANGE(3000000, 13, 14, 100000), + SPACEMIT_PMIC_REGULATOR_RANGE(3300000, 15, 15, 0), +}; + +static const struct spacemit_pmic_regulator_range pm853_ldo_ranges2[] = +{ + SPACEMIT_PMIC_REGULATOR_RANGE(1600000, 0x0, 0x3, 100000), +}; + +static const struct spacemit_pmic_regulator_range pm853_ldo_ranges3[] = +{ + SPACEMIT_PMIC_REGULATOR_RANGE(1200000, 0x0, 0xf, 50000), +}; + +static const struct spacemit_pmic_regulator_range pm853_ldo_ranges4[] = +{ + SPACEMIT_PMIC_REGULATOR_RANGE(1000000, 0x0, 0x7, 50000), +}; + +static const struct spacemit_pmic_regulator_desc pm853_reg[] = +{ + /* BUCK */ + PM853_DESC(PM853_ID_DCDC1, "DCDC_REG1", "vcc_sys", + 128, PM853_BUCK1_VSEL_REG, PM853_BUCK1_VSEL_MSK, + PM853_LDO_BUCK_EN_REG0, PM853_BUCK1_EN_MSK, + pm853_buck_ranges1), + + PM853_DESC(PM853_ID_DCDC2, "DCDC_REG2", "vcc_sys", + 128, PM853_BUCK2_VSEL_REG, PM853_BUCK2_VSEL_MSK, + PM853_LDO_BUCK_EN_REG0, PM853_BUCK2_EN_MSK, + pm853_buck_ranges2), + + PM853_DESC(PM853_ID_DCDC3, "DCDC_REG3", "vcc_sys", + 128, PM853_BUCK3_VSEL_REG, PM853_BUCK3_VSEL_MSK, + PM853_LDO_BUCK_EN_REG0, PM853_BUCK3_EN_MSK, + pm853_buck_ranges2), + + PM853_DESC(PM853_ID_DCDC4, "DCDC_REG4", "vcc_sys", + 128, PM853_BUCK4_VSEL_REG, PM853_BUCK4_VSEL_MSK, + PM853_LDO_BUCK_EN_REG0, PM853_BUCK4_EN_MSK, + pm853_buck_ranges1), + + PM853_DESC(PM853_ID_DCDC5, "DCDC_REG5", "vcc_sys", + 128, PM853_BUCK5_VSEL_REG, PM853_BUCK5_VSEL_MSK, + PM853_LDO_BUCK_EN_REG0, PM853_BUCK5_EN_MSK, + pm853_buck_ranges2), + + /* ALDO */ + PM853_DESC(PM853_ID_LDO1, "LDO_REG1", "vcc_sys", + 16, PM853_LDO1_VSEL_REG, PM853_LDO_VSEL_MSK, + PM853_LDO_BUCK_EN_REG0, PM853_LDO1_EN_MSK, + pm853_ldo_ranges1), + + PM853_DESC(PM853_ID_LDO2, "LDO_REG2", "vcc_sys", + 16, PM853_LDO2_VSEL_REG, PM853_LDO_VSEL_MSK, + PM853_LDO_BUCK_EN_REG0, PM853_LDO2_EN_MSK, + pm853_ldo_ranges1), + + PM853_DESC(PM853_ID_LDO3, "LDO_REG3", "vcc_sys", + 16, PM853_LDO3_VSEL_REG, PM853_LDO_VSEL_MSK, + PM853_LDO_BUCK_EN_REG0, PM853_LDO3_EN_MSK, + pm853_ldo_ranges1), + + PM853_DESC(PM853_ID_LDO4, "LDO_REG4", "vcc_sys", + 16, PM853_LDO4_VSEL_REG, PM853_LDO_VSEL_MSK, + PM853_LDO_BUCK_EN_REG1, PM853_LDO4_EN_MSK, + pm853_ldo_ranges1), + + PM853_DESC(PM853_ID_LDO5, "LDO_REG5", "vcc_sys", + 4, PM853_LDO5_VSEL_REG, PM853_LDO_VSEL_MSK, + PM853_LDO_BUCK_EN_REG1, PM853_LDO5_EN_MSK, + pm853_ldo_ranges2), + + PM853_DESC(PM853_ID_LDO6, "LDO_REG6", "vcc_sys", + 16, PM853_LDO6_VSEL_REG, PM853_LDO_VSEL_MSK, + PM853_LDO_BUCK_EN_REG1, PM853_LDO6_EN_MSK, + pm853_ldo_ranges1), + + PM853_DESC(PM853_ID_LDO7, "LDO_REG7", "dcdc2", + 16, PM853_LDO7_VSEL_REG, PM853_LDO_VSEL_MSK, + PM853_LDO_BUCK_EN_REG1, PM853_LDO7_EN_MSK, + pm853_ldo_ranges3), + + PM853_DESC(PM853_ID_LDO8, "LDO_REG8", "vcc_sys", + 16, PM853_LDO8_VSEL_REG, PM853_LDO_VSEL_MSK, + PM853_LDO_BUCK_EN_REG1, PM853_LDO8_EN_MSK, + pm853_ldo_ranges1), + + PM853_DESC(PM853_ID_LDO9, "LDO_REG9", "vcc_sys", + 16, PM853_LDO9_VSEL_REG, PM853_LDO_VSEL_MSK, + PM853_LDO_BUCK_EN_REG1, PM853_LDO9_EN_MSK, + pm853_ldo_ranges1), + + PM853_DESC(PM853_ID_LDO10, "LDO_REG10", "vcc_sys", + 16, PM853_LDO10_VSEL_REG, PM853_LDO_VSEL_MSK, + PM853_LDO_BUCK_EN_REG1, PM853_LDO10_EN_MSK, + pm853_ldo_ranges1), + + PM853_DESC(PM853_ID_LDO11, "LDO_REG11", "dcdc2", + 16, PM853_LDO11_VSEL_REG, PM853_LDO_VSEL_MSK, + PM853_LDO_BUCK_EN_REG1, PM853_LDO11_EN_MSK, + pm853_ldo_ranges3), + + PM853_DESC(PM853_ID_LDO12, "LDO_REG12", "vcc_sys", + 16, PM853_LDO12_VSEL_REG, PM853_LDO_VSEL_MSK, + PM853_LDO_BUCK_EN_REG2, PM853_LDO12_EN_MSK, + pm853_ldo_ranges1), + + PM853_DESC(PM853_ID_LDO13, "LDO_REG13", "vcc_sys", + 16, PM853_LDO13_VSEL_REG, PM853_LDO_VSEL_MSK, + PM853_LDO_BUCK_EN_REG2, PM853_LDO13_EN_MSK, + pm853_ldo_ranges1), + + PM853_DESC(PM853_ID_LDO14, "LDO_REG14", "vcc_sys", + 16, PM853_LDO14_VSEL_REG, PM853_LDO_VSEL_MSK, + PM853_LDO_BUCK_EN_REG2, PM853_LDO14_EN_MSK, + pm853_ldo_ranges1), + + PM853_DESC(PM853_ID_LDO15, "LDO_REG15", "dcdc2", + 16, PM853_LDO15_VSEL_REG, PM853_LDO_VSEL_MSK, + PM853_LDO_BUCK_EN_REG2, PM853_LDO15_EN_MSK, + pm853_ldo_ranges3), + + PM853_DESC(PM853_ID_LDO16, "LDO_REG16", "vcc_sys", + 16, PM853_LDO16_VSEL_REG, PM853_LDO_VSEL_MSK, + PM853_LDO_BUCK_EN_REG2, PM853_LDO16_EN_MSK, + pm853_ldo_ranges1), + + PM853_DESC(PM853_ID_LDO17, "LDO_REG17", "dcdc5", + 8, PM853_LDO17_VSEL_REG, PM853_LDO_VSEL_MSK, + PM853_LDO_BUCK_EN_REG2, PM853_LDO17_EN_MSK, + pm853_ldo_ranges4), + + PM853_DESC(PM853_ID_LDO18, "LDO_REG18", "dcdc2", + 16, PM853_LDO18_VSEL_REG, PM853_LDO_VSEL_MSK, + PM853_LDO_BUCK_EN_REG2, PM853_LDO18_EN_MSK, + pm853_ldo_ranges3), + + PM853_DESC(PM853_ID_LDO19, "LDO_REG19", "dcdc5", + 8, PM853_LDO19_VSEL_REG, PM853_LDO_VSEL_MSK, + PM853_LDO_BUCK_EN_REG2, PM853_LDO19_EN_MSK, + pm853_ldo_ranges4), + + PM853_DESC(PM853_ID_LDO20, "LDO_REG20", "dcdc5", + 8, PM853_LDO20_VSEL_REG, PM853_LDO_VSEL_MSK, + PM853_LDO_BUCK_EN_REG3, PM853_LDO20_EN_MSK, + pm853_ldo_ranges4), + + PM853_DESC(PM853_ID_LDO21, "LDO_REG21", "dcdc2", + 16, PM853_LDO21_VSEL_REG, PM853_LDO_VSEL_MSK, + PM853_LDO_BUCK_EN_REG3, PM853_LDO21_EN_MSK, + pm853_ldo_ranges3), + + PM853_DESC(PM853_ID_LDO22, "LDO_REG22", "dcdc5", + 8, PM853_LDO22_VSEL_REG, PM853_LDO_VSEL_MSK, + PM853_LDO_BUCK_EN_REG3, PM853_LDO22_EN_MSK, + pm853_ldo_ranges4), + + /* PWR SWITCH */ + PM853_DESC_SWITCH(PM853_ID_LDO5_SW, "SWITCH_REG1", "vcc_sys", + PM853_LDO_BUCK_EN_REG3, PM853_SW_EN_MSK), +}; + +static struct spacemit_pmic_regulator_data pm853_regulator_data = +{ + .desc = pm853_reg, + .desc_nr = RT_ARRAY_SIZE(pm853_reg), +}; +#endif /* __SPACEMIT_REGULATOR_INTERNAL */ + +#ifdef __SPACEMIT_PMIC_INTERNAL +static struct spacemit_pmic_mfd_endpoint pm853_mfd_endpoint[] = +{ + { + .ofw_name = "spacemit-regulator@pm853", + .ofw_compatible = "pmic,regulator,pm853", + }, +}; + +static struct spacemit_pmic_mfd_data pm853_mfd_data = +{ + .regmap_cfg = + { + .reg_bits = 8, + .val_bits = 8, + .max_register = SPACEMIT_PM853_MAX_REG, + }, + .endpoint = pm853_mfd_endpoint, + .endpoint_num = RT_ARRAY_SIZE(pm853_mfd_endpoint), +}; +#endif /* __SPACEMIT_PMIC_INTERNAL */ + +#endif /* __PM853_H__ */ diff --git a/bsp/spacemit/dm/include/mfd/spacemit-pmic.h b/bsp/spacemit/dm/include/mfd/spacemit-pmic.h new file mode 100644 index 000000000000..a843d66e7fa6 --- /dev/null +++ b/bsp/spacemit/dm/include/mfd/spacemit-pmic.h @@ -0,0 +1,483 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __SPACEMIT_PMIC_H__ +#define __SPACEMIT_PMIC_H__ + +#include +#include + +struct spacemit_pmic_mfd_data; + +struct spacemit_pmic +{ + int irq; + int addr_offset; + struct rt_device *dev; + rt_mutex_t io_lock; + const struct spacemit_pmic_mfd_data *mfd_data; + + unsigned (*read)(struct spacemit_pmic *pmic, unsigned reg); + rt_err_t (*write)(struct spacemit_pmic *pmic, unsigned reg, unsigned data); + rt_err_t (*write_bit)(struct spacemit_pmic *pmic, unsigned reg, unsigned mask, unsigned data); + rt_err_t (*update_bits)(struct spacemit_pmic *pmic, unsigned reg, unsigned mask, unsigned data); +}; + +struct spacemit_pmic_irq_map +{ + rt_uint32_t reg_offset; + rt_uint32_t mask; +}; + +struct spacemit_pmic_irqchip +{ + struct rt_pic parent; + + struct spacemit_pmic *pmic; + + rt_uint32_t *irq_status; + + int num_regs; + int reg_stride; + int mask_base; + int status_base; + int ack_base; + + rt_bool_t init_ack_masked; + rt_bool_t mask_unmask_non_inverted; + + int irqs_nr; + const struct spacemit_pmic_irq_map *irqs_map; + + struct rt_thread *irq_thread; + struct rt_semaphore irq_sem; + + volatile rt_uint32_t hard_irq_count; + volatile rt_uint32_t worker_count; + volatile rt_uint32_t rearm_count; +}; + +#define raw_to_spacemit_pmic_irqchip(raw) rt_container_of(raw, struct spacemit_pmic_irqchip, parent) + +struct spacemit_pmic_regmap_config +{ + rt_uint8_t reg_bits; + rt_uint8_t val_bits; + rt_uint16_t max_register; +}; + +struct spacemit_pmic_mfd_endpoint +{ + const char *ofw_name; + const char *ofw_compatible; + + int irqs_nr; + const int *irqs_list; +}; + +struct spacemit_pmic_mfd_data +{ + struct spacemit_pmic_regmap_config regmap_cfg; + + struct spacemit_pmic_mfd_endpoint *endpoint; + rt_uint32_t endpoint_num; + + struct spacemit_pmic_irqchip *irqchip; + + /* Shutdown - reboot support */ + struct + { + rt_uint8_t reg; + rt_uint8_t bit; + } shutdown; + + struct + { + rt_uint32_t reg; + rt_uint8_t bit; + } reboot; + + /* Value will be kept in register while reset pmic */ + struct + { + rt_uint32_t reg; + rt_uint8_t bit; + } non_reset; +}; + +/* Regulator */ +struct spacemit_pmic_regulator_range +{ + int min; + int min_sel; + int max_sel; + int step; +}; + +#define SPACEMIT_PMIC_REGULATOR_RANGE(UVOLT_MIN, MIN_SEL, MAX_SEL, UVOLT_STEP) \ +{ \ + .min = UVOLT_MIN, \ + .min_sel = MIN_SEL, \ + .max_sel = MAX_SEL, \ + .step = UVOLT_STEP, \ +} + +struct spacemit_pmic_regulator_desc +{ + const char *name; + const char *match; + const char *supply_name; + + const struct rt_regulator_ops *ops; + + rt_uint32_t id; + + int voltages_nr; + int uvolt_min; + int uvolt_step; + + int ranges_nr; + const struct spacemit_pmic_regulator_range *ranges; + + rt_uint32_t vsel_reg; + rt_uint32_t vsel_mask; + rt_uint32_t enable_reg; + rt_uint32_t enable_mask; + rt_uint32_t enable_val; + rt_uint32_t disable_val; +}; + +#define SPACEMIT_PMIC_REGULATOR_DESC(ID, NAME, \ + SUPPLY_NAME, OPS, \ + VOLTAGES_NR, UVOLT_MIN, UVOLT_STEP, \ + RANGES_NR, RANGES, \ + VSEL_REG, VSEL_MASK, ENABLE_REG, \ + ENABLE_MASK, ENABLE_VAL, DISABLE_VAL) \ +{ \ + .name = NAME, \ + .supply_name = SUPPLY_NAME, \ + .ops = &OPS, \ + .id = ID, \ + .voltages_nr = VOLTAGES_NR, \ + .uvolt_min = UVOLT_MIN, \ + .uvolt_step = UVOLT_STEP, \ + .ranges_nr = RANGES_NR, \ + .ranges = RANGES, \ + .vsel_reg = VSEL_REG, \ + .vsel_mask = VSEL_MASK, \ + .enable_reg = ENABLE_REG, \ + .enable_mask = ENABLE_MASK, \ + .enable_val = ENABLE_VAL, \ + .disable_val = DISABLE_VAL, \ +} + +#define SPACEMIT_PMIC_REGULATOR_DESC_COMMON(ID, \ + NAME, SUPPLY_NAME, VOLTAGES_NR, VSEL_REG, \ + VSEL_MASK, ENABLE_REG, ENABLE_MASK, RANGES, \ + OPS) \ + SPACEMIT_PMIC_REGULATOR_DESC(ID, NAME, \ + SUPPLY_NAME, OPS, \ + VOLTAGES_NR, 0, 0, \ + RT_ARRAY_SIZE(RANGES), RANGES, \ + VSEL_REG, VSEL_MASK, ENABLE_REG, \ + ENABLE_MASK, 0, 0) + +#define SPACEMIT_PMIC_REGULATOR_DESC_SWITCH_COM(\ + ID, NAME, SUPPLY_NAME, \ + ENABLE_REG, ENABLE_MASK, \ + ENABLE_VAL, DISABLE_VAL, OPS) \ + SPACEMIT_PMIC_REGULATOR_DESC(ID, NAME, \ + SUPPLY_NAME, OPS, \ + 0, 0, 0, \ + 0, RT_NULL, \ + 0, 0, ENABLE_REG, \ + ENABLE_MASK, ENABLE_VAL, DISABLE_VAL) + +struct spacemit_pmic_regulator_data +{ + const struct spacemit_pmic_regulator_desc *desc; + rt_uint32_t desc_nr; + int sleep_reg_offset; +}; + +/* Pinctrl */ +struct spacemit_pmic_pin_func_desc +{ + const char *name; + rt_uint8_t pin_id; + rt_uint8_t func_reg; + rt_uint8_t func_mask; + rt_uint8_t en_val; + rt_uint8_t ha_sub; + rt_uint8_t sub_reg; + rt_uint8_t sub_mask; + rt_uint8_t sube_val; +}; + +#define SPM8XX_DESC_PIN_FUNC_COM(_pin_id, _match, \ + _ereg, _emask, _enval, \ + _hsub, _subreg, _submask, _subenval) \ +{ \ + .name = (_match), \ + .pin_id = (_pin_id), \ + .func_reg = (_ereg), \ + .func_mask = (_emask), \ + .en_val = (_enval), \ + .ha_sub = (_hsub), \ + .sub_reg = (_subreg), \ + .sub_mask = (_submask), \ + .sube_val = (_subenval), \ +} + +struct spacemit_pmic_pin_config_desc +{ + rt_uint32_t pin_id; + /* Input config desc */ + struct + { + rt_uint8_t reg; + rt_uint8_t msk; + } input; + + /* Output config desc */ + struct + { + rt_uint8_t reg; + rt_uint8_t msk; + } output; + + /* Pull-down desc */ + struct + { + rt_uint8_t reg; + rt_uint8_t msk; + } pup; + + /* Deb */ + struct + { + rt_uint8_t reg; + rt_uint8_t timemsk; + + struct + { + rt_uint8_t msk; + } en; + } deb; + + /* OD */ + struct + { + rt_uint8_t reg; + rt_uint8_t msk; + } od; + + struct + { + rt_uint8_t reg; + rt_uint8_t msk; + } itype; +}; + +#define SPM8XX_DESC_PIN_CONFIG_COM(_pin_id, \ + _ireg, _imsk, _oreg, _omsk, \ + _pureg, _pumsk, \ + _debreg, _debtmsk, _debemsk, \ + _odreg, _odmsk, \ + _itypereg, _itypemsk) \ +{ \ + .pin_id = (_pin_id), \ + .input = \ + { \ + .reg = (_ireg), \ + .msk = (_imsk), \ + }, \ + .output = \ + { \ + .reg = (_oreg), \ + .msk = (_omsk), \ + }, \ + .pup = \ + { \ + .reg = (_pureg), \ + .msk = (_pumsk), \ + }, \ + .deb = \ + { \ + .reg = (_debreg), \ + .timemsk = (_debtmsk), \ + .en.msk = (_debemsk) \ + }, \ + .od = \ + { \ + .reg = (_odreg), \ + .msk = (_odmsk), \ + }, \ + .itype = \ + { \ + .reg = (_itypereg), \ + .msk = (_itypemsk), \ + }, \ +} + +struct spacemit_pmic_pin_data +{ + int pin_mux_nr; + const char **pinmux_funcs; + + int pin_fuc_desc_nr; + const struct spacemit_pmic_pin_func_desc *pinfunc_desc; + + int pin_conf_desc_nr; + const struct spacemit_pmic_pin_config_desc *pinconf_desc; +}; + +/* RTC */ +union spacemit_pmic_rtc_ctl_desc +{ + rt_uint32_t val; + struct + { + rt_uint32_t crystal_en:1; + rt_uint32_t out_32k_en:1; + rt_uint32_t rtc_en:1; + rt_uint32_t rtc_clk_sel:1; + rt_uint32_t tick_type:1; + rt_uint32_t alarm_en:1; + rt_uint32_t tick_en:1; + rt_uint32_t reserved:25; + } bits; +}; + +struct spacemit_pmic_rtc_regdesc +{ + /* Seconds */ + struct + { + rt_uint8_t reg; + rt_uint8_t msk; + } cnt_s; + + /* Mini */ + struct + { + rt_uint8_t reg; + rt_uint8_t msk; + } cnt_mi; + + /* Hour */ + struct + { + rt_uint8_t reg; + rt_uint8_t msk; + } cnt_h; + + /* Day */ + struct + { + rt_uint8_t reg; + rt_uint8_t msk; + } cnt_d; + + /* Mounth */ + struct + { + rt_uint8_t reg; + rt_uint8_t msk; + } cnt_mo; + + /* Year */ + struct + { + rt_uint8_t reg; + rt_uint8_t msk; + } cnt_y; + + struct + { + rt_uint8_t reg; + rt_uint8_t msk; + } alarm_s; + + struct + { + rt_uint8_t reg; + rt_uint8_t msk; + } alarm_mi; + + struct + { + rt_uint8_t reg; + rt_uint8_t msk; + } alarm_h; + + struct + { + rt_uint8_t reg; + rt_uint8_t msk; + } alarm_d; + + struct + { + rt_uint8_t reg; + rt_uint8_t msk; + } alarm_mo; + + struct + { + rt_uint8_t reg; + rt_uint8_t msk; + } alarm_y; + + struct + { + rt_uint8_t reg; + } rtc_ctl; +}; + +/* IIO */ +struct spacemit_pmic_iio_chan_spec +{ + int channel; +}; + +struct spacemit_pmic_adc_data +{ + int iio_desc_nr; + struct spacemit_pmic_iio_chan_spec *iio_desc; +}; + +#include "spm8821.h" +#include "pm853.h" +#include "sy8810l.h" + +rt_inline unsigned spacemit_pmic_read(struct spacemit_pmic *pmic, unsigned reg) +{ + return pmic->read(pmic, reg); +} + +rt_inline rt_err_t spacemit_pmic_write(struct spacemit_pmic *pmic, unsigned reg, unsigned data) +{ + return pmic->write(pmic, reg, data); +} + +rt_inline rt_err_t spacemit_pmic_write_bit(struct spacemit_pmic *pmic, unsigned reg, + unsigned mask, unsigned data) +{ + return pmic->write_bit(pmic, reg, mask, data); +} + +rt_inline rt_err_t spacemit_pmic_update_bits(struct spacemit_pmic *pmic, unsigned reg, + unsigned mask, unsigned data) +{ + return pmic->update_bits(pmic, reg, mask, data); +} + +#endif /* __SPACEMIT_PMIC_H__ */ diff --git a/bsp/spacemit/dm/include/mfd/spm8821.h b/bsp/spacemit/dm/include/mfd/spm8821.h new file mode 100644 index 000000000000..c93ffcb600f0 --- /dev/null +++ b/bsp/spacemit/dm/include/mfd/spm8821.h @@ -0,0 +1,885 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __SMP8821_H__ +#define __SMP8821_H__ + +enum +{ + SPM8821_ID_DCDC1, + SPM8821_ID_DCDC2, + SPM8821_ID_DCDC3, + SPM8821_ID_DCDC4, + SPM8821_ID_DCDC5, + SPM8821_ID_DCDC6, + SPM8821_ID_LDO1, + SPM8821_ID_LDO2, + SPM8821_ID_LDO3, + SPM8821_ID_LDO4, + SPM8821_ID_LDO5, + SPM8821_ID_LDO6, + SPM8821_ID_LDO7, + SPM8821_ID_LDO8, + SPM8821_ID_LDO9, + SPM8821_ID_LDO10, + SPM8821_ID_LDO11, + SPM8821_ID_SWITCH1, +}; + +#define SPACEMIT_SPM8821_MAX_REG 0xb0 + +#define SPM8821_VERSION_ID_REG 0xa1 + +#define SPM8821_BUCK_VSEL_MASK 0xff +#define SMP8821_BUCK_EN_MASK 0x1 + +#define SPM8821_BUCK1_CTRL_REG 0x47 +#define SPM8821_BUCK2_CTRL_REG 0x4a +#define SPM8821_BUCK3_CTRL_REG 0x4d +#define SPM8821_BUCK4_CTRL_REG 0x50 +#define SPM8821_BUCK5_CTRL_REG 0x53 +#define SPM8821_BUCK6_CTRL_REG 0x56 + +#define SPM8821_BUCK1_VSEL_REG 0x48 +#define SPM8821_BUCK2_VSEL_REG 0x4b +#define SPM8821_BUCK3_VSEL_REG 0x4e +#define SPM8821_BUCK4_VSEL_REG 0x51 +#define SPM8821_BUCK5_VSEL_REG 0x54 +#define SPM8821_BUCK6_VSEL_REG 0x57 + +#define SPM8821_ALDO1_CTRL_REG 0x5b +#define SPM8821_ALDO2_CTRL_REG 0x5e +#define SPM8821_ALDO3_CTRL_REG 0x61 +#define SPM8821_ALDO4_CTRL_REG 0x64 + +#define SPM8821_ALDO1_VOLT_REG 0x5c +#define SPM8821_ALDO2_VOLT_REG 0x5f +#define SPM8821_ALDO3_VOLT_REG 0x62 +#define SPM8821_ALDO4_VOLT_REG 0x65 + +#define SPM8821_ALDO_EN_MASK 0x1 +#define SPM8821_ALDO_VSEL_MASK 0x7f + +#define SPM8821_DLDO1_CTRL_REG 0x67 +#define SPM8821_DLDO2_CTRL_REG 0x6a +#define SPM8821_DLDO3_CTRL_REG 0x6d +#define SPM8821_DLDO4_CTRL_REG 0x70 +#define SPM8821_DLDO5_CTRL_REG 0x73 +#define SPM8821_DLDO6_CTRL_REG 0x76 +#define SPM8821_DLDO7_CTRL_REG 0x79 + +#define SPM8821_DLDO1_VOLT_REG 0x68 +#define SPM8821_DLDO2_VOLT_REG 0x6b +#define SPM8821_DLDO3_VOLT_REG 0x6e +#define SPM8821_DLDO4_VOLT_REG 0x71 +#define SPM8821_DLDO5_VOLT_REG 0x74 +#define SPM8821_DLDO6_VOLT_REG 0x77 +#define SPM8821_DLDO7_VOLT_REG 0x7a + +#define SPM8821_DLDO_EN_MASK 0x1 +#define SPM8821_DLDO_VSEL_MASK 0x7f + +#define SPM8821_SWITCH_CTRL_REG 0x59 +#define SPM8821_SWTICH_EN_MASK 0x1 + +#define SPM8821_PWR_CTRL2 0x7e +#define SPM8821_SW_SHUTDOWN_BIT_MSK 0x4 +#define SPM8821_SW_RESET_BIT_MSK 0x2 + +#define SPM8821_NON_RESET_REG 0xab +#define SPM8821_RESTART_CFG_BIT_MSK 0x7 + +#define SPM8821_SLEEP_REG_OFFSET 0x1 + +#define SPM8821_ADC_AUTO_REG 0x22 +#define SPM8821_ADC_AUTO_BIT_MSK 0x7f + +#define SPM8821_ADC_CTRL_REG 0x1e +#define SPM8821_ADC_CTRL_BIT_MSK 0x3 +#define SPM8821_ADC_CTRL_EN_BIT_OFFSET 0x0 +#define SPM8821_ADC_CTRL_GO_BIT_OFFSET 0x1 + +#define SPM8821_ADC_CFG1_REG 0x20 + +#define SPM8821_ADC_CFG1_ADC_CHOP_EN_BIT_OFFSET 0x6 +#define SPM8821_ADC_CFG1_ADC_CHOP_EN_BIT_MSK 0x40 + +#define SPM8821_ADC_CFG1_ADC_CHNNL_SEL_BIT_OFFSET 0x3 +#define SPM8821_ADC_CFG1_ADC_CHNNL_SEL_BIT_MSK 0x38 + +#define SPM8821_ADC_CFG2_REG 0x21 +#define SPM8821_ADC_CFG2_REF_SEL_BIT_OFFSET 0x0 +#define SPM8821_ADC_CFG2_REF_SEL_BIT_MSK 0x3 +#define SPM8821_ADC_CFG2_3V3_REF 0x2 + +#define SPM8821_ADC_CFG2_7_DEB_NUM 0x7 +#define SPM8821_ADC_CFG2_DEB_NUM_BIT_MSK 0x70 +#define SPM8821_ADC_CFG2_DEB_NUM_BIT_OFFSET 0x4 + +#define SPM8821_ADC_EXTERNAL_CHANNEL_OFFSET 2 + +#define SPM8821_ADCIN0_RES_H_REG 0x2a +#define SPM8821_ADCIN0_RES_L_REG 0x2b +#define SPM8821_ADCIN0_REG_L_BIT_MSK 0xf0 + +#define SPM8821_E_STATUS_REG_BASE 0x91 +#define SPM8821_E_EN_REG_BASE 0x98 + +#define SPM8821_DESC(_id, _match, _supply, _nv, _vr, _vm, _er, _em, _lr) \ + SPACEMIT_PMIC_REGULATOR_DESC_COMMON(_id, _match, _supply, _nv, _vr, _vm, _er, _em, _lr, pmic_dcdc_ldo_ops) + +#define SPM8821_DESC_SWITCH(_id, _match, _supply, _ereg, _emask) \ + SPACEMIT_PMIC_REGULATOR_DESC_SWITCH_COM(_id, _match, _supply, _ereg, _emask, 0, 0, pmic_switch_ops) + +#ifdef __SPACEMIT_REGULATOR_INTERNAL +static const struct spacemit_pmic_regulator_range spm8821_buck_ranges[] = +{ + SPACEMIT_PMIC_REGULATOR_RANGE(500000, 0x0, 0xaa, 5000), + SPACEMIT_PMIC_REGULATOR_RANGE(1375000, 0xab, 0xff, 25000), +}; + +static const struct spacemit_pmic_regulator_range spm8821_ldo_ranges[] = +{ + SPACEMIT_PMIC_REGULATOR_RANGE(500000, 0xb, 0x7f, 25000), +}; + +static const struct spacemit_pmic_regulator_desc spm8821_reg[] = +{ + /* BUCK */ + SPM8821_DESC(SPM8821_ID_DCDC1, "DCDC_REG1", "vcc_sys", + 255, SPM8821_BUCK1_VSEL_REG, SPM8821_BUCK_VSEL_MASK, + SPM8821_BUCK1_CTRL_REG, SMP8821_BUCK_EN_MASK, + spm8821_buck_ranges), + + SPM8821_DESC(SPM8821_ID_DCDC2, "DCDC_REG2", "vcc_sys", + 255, SPM8821_BUCK2_VSEL_REG, SPM8821_BUCK_VSEL_MASK, + SPM8821_BUCK2_CTRL_REG, SMP8821_BUCK_EN_MASK, + spm8821_buck_ranges), + + SPM8821_DESC(SPM8821_ID_DCDC3, "DCDC_REG3", "vcc_sys", + 255, SPM8821_BUCK3_VSEL_REG, SPM8821_BUCK_VSEL_MASK, + SPM8821_BUCK3_CTRL_REG, SMP8821_BUCK_EN_MASK, + spm8821_buck_ranges), + + SPM8821_DESC(SPM8821_ID_DCDC4, "DCDC_REG4", "vcc_sys", + 255, SPM8821_BUCK4_VSEL_REG, SPM8821_BUCK_VSEL_MASK, + SPM8821_BUCK4_CTRL_REG, SMP8821_BUCK_EN_MASK, + spm8821_buck_ranges), + + SPM8821_DESC(SPM8821_ID_DCDC5, "DCDC_REG5", "vcc_sys", + 255, SPM8821_BUCK5_VSEL_REG, SPM8821_BUCK_VSEL_MASK, + SPM8821_BUCK5_CTRL_REG, SMP8821_BUCK_EN_MASK, + spm8821_buck_ranges), + + SPM8821_DESC(SPM8821_ID_DCDC6, "DCDC_REG6", "vcc_sys", + 255, SPM8821_BUCK6_VSEL_REG, SPM8821_BUCK_VSEL_MASK, + SPM8821_BUCK6_CTRL_REG, SMP8821_BUCK_EN_MASK, + spm8821_buck_ranges), + /* ALDO */ + SPM8821_DESC(SPM8821_ID_LDO1, "LDO_REG1", "vcc_sys", + 128, SPM8821_ALDO1_VOLT_REG, SPM8821_ALDO_VSEL_MASK, + SPM8821_ALDO1_CTRL_REG, SPM8821_ALDO_EN_MASK, spm8821_ldo_ranges), + + SPM8821_DESC(SPM8821_ID_LDO2, "LDO_REG2", "vcc_sys", + 128, SPM8821_ALDO2_VOLT_REG, SPM8821_ALDO_VSEL_MASK, + SPM8821_ALDO2_CTRL_REG, SPM8821_ALDO_EN_MASK, spm8821_ldo_ranges), + + SPM8821_DESC(SPM8821_ID_LDO3, "LDO_REG3", "vcc_sys", + 128, SPM8821_ALDO3_VOLT_REG, SPM8821_ALDO_VSEL_MASK, + SPM8821_ALDO3_CTRL_REG, SPM8821_ALDO_EN_MASK, spm8821_ldo_ranges), + + SPM8821_DESC(SPM8821_ID_LDO4, "LDO_REG4", "vcc_sys", + 128, SPM8821_ALDO4_VOLT_REG, SPM8821_ALDO_VSEL_MASK, + SPM8821_ALDO4_CTRL_REG, SPM8821_ALDO_EN_MASK, spm8821_ldo_ranges), + + /* DLDO */ + SPM8821_DESC(SPM8821_ID_LDO5, "LDO_REG5", "dcdc5", + 128, SPM8821_DLDO1_VOLT_REG, SPM8821_DLDO_VSEL_MASK, + SPM8821_DLDO1_CTRL_REG, SPM8821_DLDO_EN_MASK, spm8821_ldo_ranges), + + SPM8821_DESC(SPM8821_ID_LDO6, "LDO_REG6", "dcdc5", + 128, SPM8821_DLDO2_VOLT_REG, SPM8821_DLDO_VSEL_MASK, + SPM8821_DLDO2_CTRL_REG, SPM8821_DLDO_EN_MASK, spm8821_ldo_ranges), + + SPM8821_DESC(SPM8821_ID_LDO7, "LDO_REG7", "dcdc5", + 128, SPM8821_DLDO3_VOLT_REG, SPM8821_DLDO_VSEL_MASK, + SPM8821_DLDO3_CTRL_REG, SPM8821_DLDO_EN_MASK, spm8821_ldo_ranges), + + SPM8821_DESC(SPM8821_ID_LDO8, "LDO_REG8", "dcdc5", + 128, SPM8821_DLDO4_VOLT_REG, SPM8821_DLDO_VSEL_MASK, + SPM8821_DLDO4_CTRL_REG, SPM8821_DLDO_EN_MASK, spm8821_ldo_ranges), + + SPM8821_DESC(SPM8821_ID_LDO9, "LDO_REG9", "dcdc5", + 128, SPM8821_DLDO5_VOLT_REG, SPM8821_DLDO_VSEL_MASK, + SPM8821_DLDO5_CTRL_REG, SPM8821_DLDO_EN_MASK, spm8821_ldo_ranges), + + SPM8821_DESC(SPM8821_ID_LDO10, "LDO_REG10", "dcdc5", + 128, SPM8821_DLDO6_VOLT_REG, SPM8821_DLDO_VSEL_MASK, + SPM8821_DLDO6_CTRL_REG, SPM8821_DLDO_EN_MASK, spm8821_ldo_ranges), + + SPM8821_DESC(SPM8821_ID_LDO11, "LDO_REG11", "dcdc5", + 128, SPM8821_DLDO7_VOLT_REG, SPM8821_DLDO_VSEL_MASK, + SPM8821_DLDO7_CTRL_REG, SPM8821_DLDO_EN_MASK, spm8821_ldo_ranges), + + /* PWR SWITCH */ + SPM8821_DESC_SWITCH(SPM8821_ID_SWITCH1, "SWITCH_REG1", "vcc_sys", + SPM8821_SWITCH_CTRL_REG, SPM8821_SWTICH_EN_MASK), +}; + +static struct spacemit_pmic_regulator_data spm8821_regulator_data = +{ + .desc = spm8821_reg, + .desc_nr = RT_ARRAY_SIZE(spm8821_reg), + .sleep_reg_offset = SPM8821_SLEEP_REG_OFFSET, +}; +#endif /* __SPACEMIT_REGULATOR_INTERNAL */ + +#ifdef __SPACEMIT_PINCTRL_INTERNAL +const char *spm8821_pinmux_functions[] = +{ + "gpioin", "gpioout", "exten", "pwrctrl", "sleep", "nreset", "adcin" +}; + +static const struct spacemit_pmic_pin_func_desc spm8821_pinfunc_desc[] = +{ + /* PIN0 gpioin */ + SPM8XX_DESC_PIN_FUNC_COM(0, "gpioin", 0x8, 0x3, 0, 0, 0, 0, 0), + /* PIN0 gpioout*/ + SPM8XX_DESC_PIN_FUNC_COM(0, "gpioout", 0x8, 0x3, 1, 0, 0, 0, 0), + /* PIN0 exten */ + SPM8XX_DESC_PIN_FUNC_COM(0, "exten", 0x8, 0x3, 0x3, 1, 0xa, 0x7, 0x0), + /* PIN0 pwrctrl */ + SPM8XX_DESC_PIN_FUNC_COM(0, "pwrctrl", 0x8, 0x3, 0x3, 1, 0xa, 0x7, 0x1), + /* PIN0 sleep */ + SPM8XX_DESC_PIN_FUNC_COM(0, "sleep", 0x8, 0x3, 0x3, 1, 0xa, 0x7, 0x2), + /* PIN0 nreset */ + SPM8XX_DESC_PIN_FUNC_COM(0, "nreset", 0x8, 0x3, 0x3, 1, 0xa, 0x7, 0x3), + /* PIN0 adcin */ + SPM8XX_DESC_PIN_FUNC_COM(0, "adcin", 0x8, 0x3, 0x3, 1, 0xa, 0x7, 0x4), + /* PIN1 gpioin */ + SPM8XX_DESC_PIN_FUNC_COM(1, "gpioin", 0x8, 0xc, 0, 0, 0, 0, 0), + /* PIN1 gpioout*/ + SPM8XX_DESC_PIN_FUNC_COM(1, "gpioout", 0x8, 0xc, 1, 0, 0, 0, 0), + /* PIN1 exten */ + SPM8XX_DESC_PIN_FUNC_COM(1, "exten", 0x8, 0xc, 0x3, 1, 0xa, 0x38, 0x0), + /* PIN1 pwrctrl */ + SPM8XX_DESC_PIN_FUNC_COM(1, "pwrctrl", 0x8, 0xc, 0x3, 1, 0xa, 0x38, 0x1), + /* PIN1 sleep */ + SPM8XX_DESC_PIN_FUNC_COM(1, "sleep", 0x8, 0xc, 0x3, 1, 0xa, 0x38, 0x2), + /* PIN1 nreset */ + SPM8XX_DESC_PIN_FUNC_COM(1, "nreset", 0x8, 0xc, 0x3, 1, 0xa, 0x38, 0x3), + /* PIN1 adcin */ + SPM8XX_DESC_PIN_FUNC_COM(1, "adcin", 0x8, 0xc, 0x3, 1, 0xa, 0x38, 0x4), + /* PIN2 gpioin */ + SPM8XX_DESC_PIN_FUNC_COM(2, "gpioin", 0x8, 0x30, 0, 0, 0, 0, 0), + /* PIN2 gpioout*/ + SPM8XX_DESC_PIN_FUNC_COM(2, "gpioout", 0x8, 0x30, 1, 0, 0, 0, 0), + /* PIN2 exten */ + SPM8XX_DESC_PIN_FUNC_COM(2, "exten", 0x8, 0x30, 0x3, 1, 0xb, 0x7, 0x0), + /* PIN2 pwrctrl */ + SPM8XX_DESC_PIN_FUNC_COM(2, "pwrctrl", 0x8, 0x30, 0x3, 1, 0xb, 0x7, 0x1), + /* PIN2 sleep */ + SPM8XX_DESC_PIN_FUNC_COM(2, "sleep", 0x8, 0x30, 0x3, 1, 0xb, 0x7, 0x2), + /* PIN2 nreset */ + SPM8XX_DESC_PIN_FUNC_COM(2, "nreset", 0x8, 0x30, 0x3, 1, 0xb, 0x7, 0x3), + /* PIN2 adcin */ + SPM8XX_DESC_PIN_FUNC_COM(2, "adcin", 0x8, 0x30, 0x3, 1, 0xb, 0x7, 0x4), + /* PIN3 gpioin */ + SPM8XX_DESC_PIN_FUNC_COM(3, "gpioin", 0x9, 0x3, 0, 0, 0, 0, 0), + /* PIN3 gpioout*/ + SPM8XX_DESC_PIN_FUNC_COM(3, "gpioout", 0x9, 0x3, 1, 0, 0, 0, 0), + /* PIN3 exten */ + SPM8XX_DESC_PIN_FUNC_COM(3, "exten", 0x9, 0x3, 0x3, 1, 0xb, 0x38, 0x0), + /* PIN3 pwrctrl */ + SPM8XX_DESC_PIN_FUNC_COM(3, "pwrctrl", 0x9, 0x3, 0x3, 1, 0xb, 0x38, 0x1), + /* PIN3 sleep */ + SPM8XX_DESC_PIN_FUNC_COM(3, "sleep", 0x9, 0x3, 0x3, 1, 0xb, 0x38, 0x2), + /* PIN3 nreset */ + SPM8XX_DESC_PIN_FUNC_COM(3, "nreset", 0x9, 0x3, 0x3, 1, 0xb, 0x38, 0x3), + /* PIN3 adcin */ + SPM8XX_DESC_PIN_FUNC_COM(3, "adcin", 0x9, 0x3, 0x3, 1, 0xb, 0x38, 0x4), + /* PIN4 gpioin */ + SPM8XX_DESC_PIN_FUNC_COM(4, "gpioin", 0x9, 0xc, 0, 0, 0, 0, 0), + /* PIN4 gpioout*/ + SPM8XX_DESC_PIN_FUNC_COM(4, "gpioout", 0x9, 0xc, 1, 0, 0, 0, 0), + /* PIN4 exten */ + SPM8XX_DESC_PIN_FUNC_COM(4, "exten", 0x9, 0xc, 0x3, 1, 0xc, 0x7, 0x0), + /* PIN4 pwrctrl */ + SPM8XX_DESC_PIN_FUNC_COM(4, "pwrctrl", 0x9, 0xc, 0x3, 1, 0xc, 0x7, 0x1), + /* PIN4 sleep */ + SPM8XX_DESC_PIN_FUNC_COM(4, "sleep", 0x9, 0xc, 0x3, 1, 0xc, 0x7, 0x2), + /* PIN4 nreset */ + SPM8XX_DESC_PIN_FUNC_COM(4, "nreset", 0x9, 0xc, 0x3, 1, 0xc, 0x7, 0x3), + /* PIN4 adcin */ + SPM8XX_DESC_PIN_FUNC_COM(4, "adcin", 0x9, 0xc, 0x3, 1, 0xc, 0x7, 0x4), + /* PIN5 gpioin */ + SPM8XX_DESC_PIN_FUNC_COM(5, "gpioin", 0x9, 0x30, 0, 0, 0, 0, 0), + /* PIN5 gpioout*/ + SPM8XX_DESC_PIN_FUNC_COM(5, "gpioout", 0x9, 0x30, 1, 0, 0, 0, 0), + /* PIN5 exten */ + SPM8XX_DESC_PIN_FUNC_COM(5, "exten", 0x9, 0x30, 0x3, 1, 0xc, 0x38, 0x0), + /* PIN5 pwrctrl */ + SPM8XX_DESC_PIN_FUNC_COM(5, "pwrctrl", 0x9, 0x30, 0x3, 1, 0xc, 0x38, 0x1), + /* PIN5 sleep */ + SPM8XX_DESC_PIN_FUNC_COM(5, "sleep", 0x9, 0x30, 0x3, 1, 0xc, 0x38, 0x2), + /* PIN5 nreset */ + SPM8XX_DESC_PIN_FUNC_COM(5, "nreset", 0x9, 0x30, 0x3, 1, 0xc, 0x38, 0x3), + /* PIN5 adcin */ + SPM8XX_DESC_PIN_FUNC_COM(5, "adcin", 0x9, 0x30, 0x3, 1, 0xc, 0x38, 0x4), +}; + +static const struct spacemit_pmic_pin_config_desc spm8821_pinconfig_desc[] = +{ + SPM8XX_DESC_PIN_CONFIG_COM(0, 0x0, 0x1, 0x1, 0x1, 0x2, 0x3, 0x4, 0xc0, 0x1, 0x5, 0x1, 0x6, 0x3), + SPM8XX_DESC_PIN_CONFIG_COM(1, 0x0, 0x2, 0x1, 0x2, 0x2, 0xc, 0x4, 0xc0, 0x2, 0x5, 0x2, 0x6, 0xc), + SPM8XX_DESC_PIN_CONFIG_COM(2, 0x0, 0x4, 0x1, 0x4, 0x2, 0x30, 0x4, 0xc0, 0x4, 0x5, 0x4, 0x6, 0x30), + SPM8XX_DESC_PIN_CONFIG_COM(3, 0x0, 0x8, 0x1, 0x8, 0x3, 0x3, 0x4, 0xc0, 0x8, 0x5, 0x8, 0x7, 0x3), + SPM8XX_DESC_PIN_CONFIG_COM(4, 0x0, 0x10, 0x1, 0x10, 0x3, 0xc, 0x4, 0xc0, 0x10, 0x5, 0x10, 0x7, 0xc), + SPM8XX_DESC_PIN_CONFIG_COM(5, 0x0, 0x20, 0x1, 0x20, 0x3, 0x30, 0x4, 0xc0, 0x20, 0x5, 0x20, 0x7, 0x30), +}; + +static const struct spacemit_pmic_pin_data spm8821_pinctrl_data = +{ + .pin_mux_nr = RT_ARRAY_SIZE(spm8821_pinmux_functions), + .pinmux_funcs = spm8821_pinmux_functions, + .pin_fuc_desc_nr = RT_ARRAY_SIZE(spm8821_pinfunc_desc), + .pinfunc_desc = spm8821_pinfunc_desc, + .pin_conf_desc_nr = RT_ARRAY_SIZE(spm8821_pinconfig_desc), + .pinconf_desc = spm8821_pinconfig_desc, +}; +#endif /* __SPACEMIT_PINCTRL_INTERNAL */ + +#ifdef __SPACEMIT_ADC_INTERNAL +static struct spacemit_pmic_iio_chan_spec spm8821_iio_desc[] = +{ + { + .channel = 0, + }, + { + .channel = 1, + }, + { + .channel = 2, + }, + { + .channel = 3, + }, + { + .channel = 4, + }, + { + .channel = 5, + }, +}; + +static const struct spacemit_pmic_adc_data spm8821_adc_data = +{ + .iio_desc = spm8821_iio_desc, + .iio_desc_nr = RT_ARRAY_SIZE(spm8821_iio_desc), +}; +#endif /* __SPACEMIT_ADC_INTERNAL */ + +#ifdef __SPACEMIT_RTC_INTERNAL +static const struct spacemit_pmic_rtc_regdesc spm8821_regdesc = +{ + .cnt_s = + { + .reg = 0xd, + .msk = 0x3f, + }, + .cnt_mi = + { + .reg = 0xe, + .msk = 0x3f, + }, + .cnt_h = + { + .reg = 0xf, + .msk = 0x1f, + }, + .cnt_d = + { + .reg = 0x10, + .msk = 0x1f, + }, + .cnt_mo = + { + .reg = 0x11, + .msk = 0xf, + }, + .cnt_y = + { + .reg = 0x12, + .msk = 0x3f, + }, + .alarm_s = + { + .reg = 0x13, + .msk = 0x3f, + }, + .alarm_mi = + { + .reg = 0x14, + .msk = 0x3f, + }, + .alarm_h = + { + .reg = 0x15, + .msk = 0x1f, + }, + .alarm_d = + { + .reg = 0x16, + .msk = 0x1f, + }, + .alarm_mo = + { + .reg = 0x17, + .msk = 0xf, + }, + .alarm_y = + { + .reg = 0x18, + .msk = 0x3f, + }, + .rtc_ctl = + { + .reg = 0x1d, + }, +}; +#endif /* __SPACEMIT_RTC_INTERNAL */ + +#ifdef __SPACEMIT_PMIC_INTERNAL +enum +{ + /* reg: 0x91 */ + SPM8821_E_GPI0, + SPM8821_E_GPI1, + SPM8821_E_GPI2, + SPM8821_E_GPI3, + SPM8821_E_GPI4, + SPM8821_E_GPI5, + + /* reg: 0x92 */ + SPM8821_E_ADC_TEMP, + SPM8821_E_ADC_EOC, + SPM8821_E_ADC_EOS, + SPM8821_E_WDT_TO, + SPM8821_E_ALARM, + SPM8821_E_TICK, + + /* reg: 0x93 */ + SPM8821_E_LDO_OV, + SPM8821_E_LDO_UV, + SPM8821_E_LDO_SC, + SPM8821_E_SW_SC, + SPM8821_E_TEMP_WARN, + SPM8821_E_TEMP_SEVERE, + SPM8821_E_TEMP_CRIT, + + /* reg: 0x94 */ + SPM8821_E_BUCK1_OV, + SPM8821_E_BUCK2_OV, + SPM8821_E_BUCK3_OV, + SPM8821_E_BUCK4_OV, + SPM8821_E_BUCK5_OV, + SPM8821_E_BUCK6_OV, + + /* reg: 0x95 */ + SPM8821_E_BUCK1_UV, + SPM8821_E_BUCK2_UV, + SPM8821_E_BUCK3_UV, + SPM8821_E_BUCK4_UV, + SPM8821_E_BUCK5_UV, + SPM8821_E_BUCK6_UV, + + /* reg: 0x96 */ + SPM8821_E_BUCK1_SC, + SPM8821_E_BUCK2_SC, + SPM8821_E_BUCK3_SC, + SPM8821_E_BUCK4_SC, + SPM8821_E_BUCK5_SC, + SPM8821_E_BUCK6_SC, + + /* reg: 0x97 */ + SPM8821_E_PWRON_RINTR, + SPM8821_E_PWRON_FINTR, + SPM8821_E_PWRON_SINTR, + SPM8821_E_PWRON_LINTR, + SPM8821_E_PWRON_SDINTR, + SPM8821_E_VSYS_OV, +}; + +#define SPM8821_E_GPI0_MSK RT_BIT(0) +#define SPM8821_E_GPI1_MSK RT_BIT(1) +#define SPM8821_E_GPI2_MSK RT_BIT(2) +#define SPM8821_E_GPI3_MSK RT_BIT(3) +#define SPM8821_E_GPI4_MSK RT_BIT(4) +#define SPM8821_E_GPI5_MSK RT_BIT(5) + +#define SPM8821_E_ADC_TEMP_MSK RT_BIT(0) +#define SPM8821_E_ADC_EOC_MSK RT_BIT(1) +#define SPM8821_E_ADC_EOS_MSK RT_BIT(2) +#define SPM8821_E_WDT_TO_MSK RT_BIT(3) +#define SPM8821_E_ALARM_MSK RT_BIT(4) +#define SPM8821_E_TICK_MSK RT_BIT(5) + +#define SPM8821_E_LDO_OV_MSK RT_BIT(0) +#define SPM8821_E_LDO_UV_MSK RT_BIT(1) +#define SPM8821_E_LDO_SC_MSK RT_BIT(2) +#define SPM8821_E_SW_SC_MSK RT_BIT(3) +#define SPM8821_E_TEMP_WARN_MSK RT_BIT(4) +#define SPM8821_E_TEMP_SEVERE_MSK RT_BIT(5) +#define SPM8821_E_TEMP_CRIT_MSK RT_BIT(6) + +#define SPM8821_E_BUCK1_OV_MSK RT_BIT(0) +#define SPM8821_E_BUCK2_OV_MSK RT_BIT(1) +#define SPM8821_E_BUCK3_OV_MSK RT_BIT(2) +#define SPM8821_E_BUCK4_OV_MSK RT_BIT(3) +#define SPM8821_E_BUCK5_OV_MSK RT_BIT(4) +#define SPM8821_E_BUCK6_OV_MSK RT_BIT(5) + +#define SPM8821_E_BUCK1_UV_MSK RT_BIT(0) +#define SPM8821_E_BUCK2_UV_MSK RT_BIT(1) +#define SPM8821_E_BUCK3_UV_MSK RT_BIT(2) +#define SPM8821_E_BUCK4_UV_MSK RT_BIT(3) +#define SPM8821_E_BUCK5_UV_MSK RT_BIT(4) +#define SPM8821_E_BUCK6_UV_MSK RT_BIT(5) + +#define SPM8821_E_BUCK1_SC_MSK RT_BIT(0) +#define SPM8821_E_BUCK2_SC_MSK RT_BIT(1) +#define SPM8821_E_BUCK3_SC_MSK RT_BIT(2) +#define SPM8821_E_BUCK4_SC_MSK RT_BIT(3) +#define SPM8821_E_BUCK5_SC_MSK RT_BIT(4) +#define SPM8821_E_BUCK6_SC_MSK RT_BIT(5) + +#define SPM8821_E_PWRON_RINTR_MSK RT_BIT(0) +#define SPM8821_E_PWRON_FINTR_MSK RT_BIT(1) +#define SPM8821_E_PWRON_SINTR_MSK RT_BIT(2) +#define SPM8821_E_PWRON_LINTR_MSK RT_BIT(3) +#define SPM8821_E_PWRON_SDINTR_MSK RT_BIT(4) +#define SPM8821_E_VSYS_OV_MSK RT_BIT(5) + +static const struct spacemit_pmic_irq_map spm8821_irqs[] = +{ + [SPM8821_E_GPI0] = + { + .mask = SPM8821_E_GPI0_MSK, + .reg_offset = 0, + }, + [SPM8821_E_GPI1] = + { + .mask = SPM8821_E_GPI1_MSK, + .reg_offset = 0, + }, + [SPM8821_E_GPI2] = + { + .mask = SPM8821_E_GPI2_MSK, + .reg_offset = 0, + }, + [SPM8821_E_GPI3] = + { + .mask = SPM8821_E_GPI3_MSK, + .reg_offset = 0, + }, + [SPM8821_E_GPI4] = + { + .mask = SPM8821_E_GPI4_MSK, + .reg_offset = 0, + }, + [SPM8821_E_GPI5] = + { + .mask = SPM8821_E_GPI5_MSK, + .reg_offset = 0, + }, + [SPM8821_E_ADC_TEMP] = + { + .mask = SPM8821_E_ADC_TEMP_MSK, + .reg_offset = 1, + }, + [SPM8821_E_ADC_EOC] = + { + .mask = SPM8821_E_ADC_EOC_MSK, + .reg_offset = 1, + }, + [SPM8821_E_ADC_EOS] = + { + .mask = SPM8821_E_ADC_EOS_MSK, + .reg_offset = 1, + }, + [SPM8821_E_WDT_TO] = + { + .mask = SPM8821_E_WDT_TO_MSK, + .reg_offset = 1, + }, + [SPM8821_E_ALARM] = + { + .mask = SPM8821_E_ALARM_MSK, + .reg_offset = 1, + }, + [SPM8821_E_TICK] = + { + .mask = SPM8821_E_TICK_MSK, + .reg_offset = 1, + }, + [SPM8821_E_LDO_OV] = + { + .mask = SPM8821_E_LDO_OV_MSK, + .reg_offset = 2, + }, + [SPM8821_E_LDO_UV] = + { + .mask = SPM8821_E_LDO_UV_MSK, + .reg_offset = 2, + }, + [SPM8821_E_LDO_SC] = + { + .mask = SPM8821_E_LDO_SC_MSK, + .reg_offset = 2, + }, + [SPM8821_E_SW_SC] = + { + .mask = SPM8821_E_SW_SC_MSK, + .reg_offset = 2, + }, + [SPM8821_E_TEMP_WARN] = + { + .mask = SPM8821_E_TEMP_WARN_MSK, + .reg_offset = 2, + }, + [SPM8821_E_TEMP_SEVERE] = + { + .mask = SPM8821_E_TEMP_SEVERE_MSK, + .reg_offset = 2, + }, + [SPM8821_E_TEMP_CRIT] = + { + .mask = SPM8821_E_TEMP_CRIT_MSK, + .reg_offset = 2, + }, + [SPM8821_E_BUCK1_OV] = + { + .mask = SPM8821_E_BUCK1_OV_MSK, + .reg_offset = 3, + }, + [SPM8821_E_BUCK2_OV] = + { + .mask = SPM8821_E_BUCK2_OV_MSK, + .reg_offset = 3, + }, + [SPM8821_E_BUCK3_OV] = + { + .mask = SPM8821_E_BUCK3_OV_MSK, + .reg_offset = 3, + }, + [SPM8821_E_BUCK4_OV] = + { + .mask = SPM8821_E_BUCK4_OV_MSK, + .reg_offset = 3, + }, + [SPM8821_E_BUCK5_OV] = + { + .mask = SPM8821_E_BUCK5_OV_MSK, + .reg_offset = 3, + }, + [SPM8821_E_BUCK6_OV] = + { + .mask = SPM8821_E_BUCK6_OV_MSK, + .reg_offset = 3, + }, + [SPM8821_E_BUCK1_UV] = + { + .mask = SPM8821_E_BUCK1_UV_MSK, + .reg_offset = 4, + }, + [SPM8821_E_BUCK2_UV] = + { + .mask = SPM8821_E_BUCK2_UV_MSK, + .reg_offset = 4, + }, + [SPM8821_E_BUCK3_UV] = + { + .mask = SPM8821_E_BUCK3_UV_MSK, + .reg_offset = 4, + }, + [SPM8821_E_BUCK4_UV] = + { + .mask = SPM8821_E_BUCK4_UV_MSK, + .reg_offset = 4, + }, + [SPM8821_E_BUCK5_UV] = + { + .mask = SPM8821_E_BUCK5_UV_MSK, + .reg_offset = 4, + }, + [SPM8821_E_BUCK6_UV] = + { + .mask = SPM8821_E_BUCK6_UV_MSK, + .reg_offset = 4, + }, + [SPM8821_E_BUCK1_SC] = + { + .mask = SPM8821_E_BUCK1_SC_MSK, + .reg_offset = 5, + }, + [SPM8821_E_BUCK2_SC] = + { + .mask = SPM8821_E_BUCK2_SC_MSK, + .reg_offset = 5, + }, + [SPM8821_E_BUCK3_SC] = + { + .mask = SPM8821_E_BUCK3_SC_MSK, + .reg_offset = 5, + }, + [SPM8821_E_BUCK4_SC] = + { + .mask = SPM8821_E_BUCK4_SC_MSK, + .reg_offset = 5, + }, + [SPM8821_E_BUCK5_SC] = + { + .mask = SPM8821_E_BUCK5_SC_MSK, + .reg_offset = 5, + }, + [SPM8821_E_BUCK6_SC] = + { + .mask = SPM8821_E_BUCK6_SC_MSK, + .reg_offset = 5, + }, + [SPM8821_E_PWRON_RINTR] = + { + .mask = SPM8821_E_PWRON_RINTR_MSK, + .reg_offset = 6, + }, + [SPM8821_E_PWRON_FINTR] = + { + .mask = SPM8821_E_PWRON_FINTR_MSK, + .reg_offset = 6, + }, + [SPM8821_E_PWRON_SINTR] = + { + .mask = SPM8821_E_PWRON_SINTR_MSK, + .reg_offset = 6, + }, + [SPM8821_E_PWRON_LINTR] = + { + .mask = SPM8821_E_PWRON_LINTR_MSK, + .reg_offset = 6, + }, + [SPM8821_E_PWRON_SDINTR] = + { + .mask = SPM8821_E_PWRON_SDINTR_MSK, + .reg_offset = 6, + }, + [SPM8821_E_VSYS_OV] = + { + .mask = SPM8821_E_VSYS_OV_MSK, + .reg_offset = 6, + }, +}; + +static rt_uint32_t spm8821_irq_status[7]; + +static struct spacemit_pmic_irqchip spm8821_irq_chip = +{ + .num_regs = RT_ARRAY_SIZE(spm8821_irq_status), + .irq_status = spm8821_irq_status, + .reg_stride = 1, + .status_base = SPM8821_E_STATUS_REG_BASE, + .mask_base = SPM8821_E_EN_REG_BASE, + .ack_base = SPM8821_E_STATUS_REG_BASE, + .init_ack_masked = RT_TRUE, + .mask_unmask_non_inverted = RT_TRUE, + .irqs_map = spm8821_irqs, + .irqs_nr = RT_ARRAY_SIZE(spm8821_irqs), +}; + +static const int spm8821_pwrkey_irqs[] = +{ + SPM8821_E_PWRON_RINTR, + SPM8821_E_PWRON_FINTR, + SPM8821_E_PWRON_SINTR, + SPM8821_E_PWRON_LINTR, +}; + +static const int spm8821_rtc_irqs[] = +{ + SPM8821_E_ALARM, +}; + +static const int spm8821_adc_irqs[] = +{ + SPM8821_E_ADC_EOC, +}; + +static struct spacemit_pmic_mfd_endpoint spm8821_mfd_endpoint[] = +{ + { + .ofw_name = "spacemit-regulator@spm8821", + .ofw_compatible = "pmic,regulator,spm8821", + }, + { + .ofw_name = "spacemit-pinctrl@spm8821", + .ofw_compatible = "pmic,pinctrl,spm8821", + }, + { + .ofw_name = "spacemit-pwrkey@spm8821", + .ofw_compatible = "pmic,pwrkey,spm8821", + .irqs_nr = RT_ARRAY_SIZE(spm8821_pwrkey_irqs), + .irqs_list = spm8821_pwrkey_irqs, + }, + { + .ofw_name = "spacemit-rtc@spm8821", + .ofw_compatible = "pmic,rtc,spm8821", + .irqs_nr = RT_ARRAY_SIZE(spm8821_rtc_irqs), + .irqs_list = spm8821_rtc_irqs, + }, + { + .ofw_name = "spacemit-adc@spm8821", + .ofw_compatible = "pmic,adc,spm8821", + .irqs_nr = RT_ARRAY_SIZE(spm8821_adc_irqs), + .irqs_list = spm8821_adc_irqs, + }, +}; + +static struct spacemit_pmic_mfd_data spm8821_mfd_data = +{ + .regmap_cfg = + { + .reg_bits = 8, + .val_bits = 8, + .max_register = SPACEMIT_SPM8821_MAX_REG, + }, + + .endpoint = spm8821_mfd_endpoint, + .endpoint_num = RT_ARRAY_SIZE(spm8821_mfd_endpoint), + + .irqchip = &spm8821_irq_chip, + + .shutdown = + { + .reg = SPM8821_PWR_CTRL2, + .bit = SPM8821_SW_SHUTDOWN_BIT_MSK, + }, + .reboot = + { + .reg = SPM8821_PWR_CTRL2, + .bit = SPM8821_SW_RESET_BIT_MSK, + }, + .non_reset = + { + .reg = SPM8821_NON_RESET_REG, + .bit = SPM8821_RESTART_CFG_BIT_MSK, + }, +}; +#endif /* __SPACEMIT_PMIC_INTERNAL */ + +#endif /* __SPM8821_H__ */ diff --git a/bsp/spacemit/dm/include/mfd/sy8810l.h b/bsp/spacemit/dm/include/mfd/sy8810l.h new file mode 100644 index 000000000000..e80a9c5ba2cb --- /dev/null +++ b/bsp/spacemit/dm/include/mfd/sy8810l.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __SY8810L_H__ +#define __SY8810L_H__ + +enum +{ + SY8810L_ID_DCDC1, +}; + +#define SPACEMIT_SY8810L_MAX_REG 0x2 + +#define SY8810L_BUCK_VSEL_MASK 0x3f +#define SY8810L_BUCK_EN_MASK 0x80 + +#define SY8810L_BUCK_CTRL_REG 0x1 +#define SY8810L_BUCK_VSEL_REG 0x0 + +#define SY8810L_DESC(_id, _match, _supply, _nv, _vr, _vm, _er, _em, _lr) \ + SPACEMIT_PMIC_REGULATOR_DESC_COMMON(_id, _match, _supply, _nv, _vr, _vm, _er, _em, _lr, pmic_dcdc_ldo_ops) + +#ifdef __SPACEMIT_REGULATOR_INTERNAL +static const struct spacemit_pmic_regulator_range sy8810l_buck_ranges[] = +{ + SPACEMIT_PMIC_REGULATOR_RANGE(600000, 0x0, 0x5a, 10000), +}; + +static const struct spacemit_pmic_regulator_desc sy8810l_reg[] = +{ + /* BUCK */ + SY8810L_DESC(SY8810L_ID_DCDC1, "EDCDC_REG1", "dcdc1", + 91, SY8810L_BUCK_VSEL_REG, SY8810L_BUCK_VSEL_MASK, + SY8810L_BUCK_CTRL_REG, SY8810L_BUCK_EN_MASK, sy8810l_buck_ranges), +}; + +static struct spacemit_pmic_regulator_data sy8810l_regulator_data = +{ + .desc = sy8810l_reg, + .desc_nr = RT_ARRAY_SIZE(sy8810l_reg), +}; +#endif /* __SPACEMIT_REGULATOR_INTERNAL */ + +#ifdef __SPACEMIT_PMIC_INTERNAL +static struct spacemit_pmic_mfd_endpoint sy8810l_mfd_endpoint[] = +{ + { + .ofw_name = "spacemit-regulator@sy8810l", + .ofw_compatible = "pmic,regulator,sy8810l", + }, +}; + +static struct spacemit_pmic_mfd_data sy8810l_mfd_data = +{ + .regmap_cfg = + { + .reg_bits = 8, + .val_bits = 8, + .max_register = SPACEMIT_SY8810L_MAX_REG, + }, + .endpoint = sy8810l_mfd_endpoint, + .endpoint_num = RT_ARRAY_SIZE(sy8810l_mfd_endpoint), +}; +#endif /* __SPACEMIT_PMIC_INTERNAL */ + +#endif /* __SY8810L_H__ */ diff --git a/bsp/spacemit/dm/include/spacemit.h b/bsp/spacemit/dm/include/spacemit.h new file mode 100644 index 000000000000..587d5a3cd602 --- /dev/null +++ b/bsp/spacemit/dm/include/spacemit.h @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __SPACEMIT_H__ +#define __SPACEMIT_H__ + +#include + +#define is_aligned(x, a) (((x) & ((typeof(x))(a) - 1)) == 0) + +#define readx_poll_timeout(OP, ADDR, VAL, COND, DELAY_US, TIMEOUT_US) \ +({ \ + rt_uint64_t timeout_us = (TIMEOUT_US); \ + rt_int64_t left_ns = timeout_us * 1000L; \ + rt_ubase_t delay_us = (DELAY_US); \ + rt_uint64_t delay_ns = delay_us * 1000L; \ + for (;;) \ + { \ + (VAL) = OP(ADDR); \ + if (COND) \ + { \ + break; \ + } \ + if (timeout_us && left_ns < 0) \ + { \ + (VAL) = OP(ADDR); \ + break; \ + } \ + if (delay_us) \ + { \ + rt_hw_us_delay(delay_us); \ + if (timeout_us) \ + { \ + left_ns -= delay_ns; \ + } \ + } \ + rt_hw_cpu_relax(); \ + if (timeout_us) \ + { \ + --left_ns; \ + } \ + } \ + (COND) ? RT_EOK : -RT_ETIMEOUT; \ +}) + +#define readl_poll_timeout(ADDR, VAL, COND, DELAY_US, TIMEOUT_US) \ + readx_poll_timeout(HWREG32, ADDR, VAL, COND, DELAY_US, TIMEOUT_US) + +rt_inline rt_uint32_t fls(rt_uint32_t val) +{ + rt_uint32_t bit = 32; + + if (!val) + return 0; + if (!(val & 0xffff0000u)) + { + val <<= 16; + bit -= 16; + } + if (!(val & 0xff000000u)) + { + val <<= 8; + bit -= 8; + } + if (!(val & 0xf0000000u)) + { + val <<= 4; + bit -= 4; + } + if (!(val & 0xc0000000u)) + { + val <<= 2; + bit -= 2; + } + if (!(val & 0x80000000u)) + { + bit -= 1; + } + + return bit; +} + +#ifdef ARCH_RISCV +#include + +/* TCM enable register */ +#define CSR_TCMCFG 0x5db +#define TCM_EN _UL(0x00000001) /* TCM Access Enable */ + +rt_inline rt_uint32_t tcm_override_readl(const volatile void *addr) +{ + rt_uint32_t val; + rt_ubase_t level, tcm_csr; + + level = rt_hw_local_irq_disable(); + tcm_csr = csr_read_clear(CSR_TCMCFG, TCM_EN); + val = HWREG32(addr); + csr_set(CSR_TCMCFG, tcm_csr); + rt_hw_local_irq_enable(level); + + return val; +} + +/* i/o write on the tcm override area */ +rt_inline void tcm_override_writel(volatile void *addr, rt_uint32_t val) +{ + rt_ubase_t level, tcm_csr; + + level = rt_hw_local_irq_disable(); + tcm_csr = csr_read_clear(CSR_TCMCFG, TCM_EN); + HWREG32(addr) = val; + csr_set(CSR_TCMCFG, tcm_csr); + rt_hw_local_irq_enable(level); +} +#endif /* ARCH_RISCV */ + +#endif /* __SPACEMIT_H__ */ diff --git a/bsp/spacemit/dm/include/v2d.h b/bsp/spacemit/dm/include/v2d.h new file mode 100644 index 000000000000..65327ba81d37 --- /dev/null +++ b/bsp/spacemit/dm/include/v2d.h @@ -0,0 +1,358 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __SPACEMIT_V2D_H__ +#define __SPACEMIT_V2D_H__ + +#include +#include +#include + +#define V2D_BUFFER_MAX_SIZE (64U * 1024U * 1024U) + +typedef enum SPACEMIT_V2D_SCALER_MODE_E +{ + V2D_NO_SCALE =0, + V2D_SCALE_DOWN =1, + V2D_SCALE_UP =2, +} V2D_SCALER_MODE_E; + +typedef enum SPACEMIT_V2D_INPUT_LAYER_E +{ + V2D_INPUT_LAYER0 =0, + V2D_INPUT_LAYER1 =1, + V2D_INPUT_LAYER_NUM =2, +} V2D_INPUT_LAYER_E; + +typedef enum SPACEMIT_V2D_FUNCTION_MODE_E +{ + V2D_FUNC_DISABLE=0, + V2D_FUNC_ENABLE =1, +} V2D_FUNCTION_MODE_E; + +typedef enum SPACEMIT_V2D_DITHER_E +{ + V2D_NO_DITHER =0, + V2D_DITHER_4X4 =1, + V2D_DITHER_8X8 =2, +} V2D_DITHER_E; + +typedef enum SPACEMIT_V2D_ROTATE_ANGLE +{ + V2D_ROT_0 =0, + V2D_ROT_90 =1, + V2D_ROT_180 =2, + V2D_ROT_270 =3, + V2D_ROT_MIRROR =4, + V2D_ROT_FLIP =5, +} V2D_ROTATE_ANGLE_E; + +typedef enum SPACEMIT_V2D_BLENDCMD_E +{ + V2D_BLENDCMD_ALPHA = 0, + V2D_BLENDCMD_ROP2 = 1, + V2D_BLENDCMD_BUTT +} V2D_BLENDCMD_E; + +typedef enum SPACEMIT_V2D_MASKCMD_E +{ + V2D_MASKCMD_DISABLE = 0, + V2D_MASKCMD_NORMAL = 1, + V2D_MASKCMD_AS_VALUE = 2, + V2D_MASKCMD_BUTT +} V2D_MASKCMD_E; + +typedef enum SPACEMIT_V2D_BLENDALPHA_SOURCE_E +{ + V2D_BLENDALPHA_SOURCE_PIXEL = 0, + V2D_BLENDALPHA_SOURCE_GOLBAL = 1, + V2D_BLENDALPHA_SOURCE_MASK = 2, + V2D_BLENDALPHA_SOURCE_BUTT +} V2D_BLENDALPHA_SOURCE_E; + +typedef enum SPACEMIT_V2D_BLEND_PRE_ALPHA_FUNC_E +{ + V2D_BLEND_PRE_ALPHA_FUNC_DISABLE = 0, + V2D_BLEND_PRE_ALPHA_FUNC_GLOBAL_MULTI_SOURCE = 1, + V2D_BLEND_PRE_ALPHA_FUNC_MASK_MULTI_SOURCE = 2, + V2D_BLEND_PRE_ALPHA_FUNC_BUTT +} V2D_BLEND_PRE_ALPHA_FUNC_E; + +typedef enum SPACEMIT_V2D_BLEND_MODE_E +{ + V2D_BLEND_ZERO = 0x0, + V2D_BLEND_ONE, + V2D_BLEND_SRC_ALPHA, + V2D_BLEND_ONE_MINUS_SRC_ALPHA, + V2D_BLEND_DST_ALPHA, + V2D_BLEND_ONE_MINUS_DST_ALPHA, + V2D_BLEND_BUTT +}V2D_BLEND_MODE_E; + +typedef enum SPACEMIT_V2D_ROP2_MODE_E +{ + V2D_ROP2_BLACK =0, + V2D_ROP2_NOTMERGEPEN=1, + V2D_ROP2_MASKNOTPEN =2, + V2D_ROP2_NOTCOPYPEN =3, + V2D_ROP2_MASKPENNOT =4, + V2D_ROP2_NOT =5, + V2D_ROP2_XORPEN =6, + V2D_ROP2_NOTMASKPEN =7, + V2D_ROP2_MASKPEN =8, + V2D_ROP2_NOTXORPEN =9, + V2D_ROP2_NOP =10, + V2D_ROP2_MERGENOTPEN=11, + V2D_ROP2_COPYPEN =12, + V2D_ROP2_MERGEPENNOT=13, + V2D_ROP2_MERGEPEN =14, + V2D_ROP2_WHITE =15, + V2D_ROP2_BUTT =16 +}V2D_ROP2_MODE_E; + +typedef enum SPACEMIT_V2D_COLOR_FORMAT_E +{ + V2D_COLOR_FORMAT_RGB888 =0, + V2D_COLOR_FORMAT_RGBX8888 =1, + V2D_COLOR_FORMAT_RGBA8888 =2, + V2D_COLOR_FORMAT_ARGB8888 =3, + V2D_COLOR_FORMAT_RGB565 =4, + V2D_COLOR_FORMAT_NV12 =5, + V2D_COLOR_FORMAT_RGBA5658 =6, + V2D_COLOR_FORMAT_ARGB8565 =7, + V2D_COLOR_FORMAT_A8 =8, + V2D_COLOR_FORMAT_Y8 =9, + V2D_COLOR_FORMAT_L8_RGBA8888=10, + V2D_COLOR_FORMAT_L8_RGB888 =11, + V2D_COLOR_FORMAT_L8_RGB565 =12, + V2D_COLOR_FORMAT_BGR888 =13, + V2D_COLOR_FORMAT_BGRX8888 =14, + V2D_COLOR_FORMAT_BGRA8888 =15, + V2D_COLOR_FORMAT_ABGR8888 =16, + V2D_COLOR_FORMAT_BGR565 =17, + V2D_COLOR_FORMAT_NV21 =18, + V2D_COLOR_FORMAT_BGRA5658 =19, + V2D_COLOR_FORMAT_ABGR8565 =20, + V2D_COLOR_FORMAT_L8_BGRA8888=21, + V2D_COLOR_FORMAT_L8_BGR888 =22, + V2D_COLOR_FORMAT_L8_BGR565 =23, + V2D_COLOR_FORMAT_BUTT, +}V2D_COLOR_FORMAT_E; + +typedef enum SPACEMIT_V2D_CSC_MODE_E +{ + V2D_CSC_MODE_RGB_2_BT601WIDE =0, + V2D_CSC_MODE_BT601WIDE_2_RGB =1, + V2D_CSC_MODE_RGB_2_BT601NARROW =2, + V2D_CSC_MODE_BT601NARROW_2_RGB =3, + V2D_CSC_MODE_RGB_2_BT709WIDE =4, + V2D_CSC_MODE_BT709WIDE_2_RGB =5, + V2D_CSC_MODE_RGB_2_BT709NARROW =6, + V2D_CSC_MODE_BT709NARROW_2_RGB =7, + V2D_CSC_MODE_BT601WIDE_2_BT709WIDE =8, + V2D_CSC_MODE_BT601WIDE_2_BT709NARROW =9, + V2D_CSC_MODE_BT601WIDE_2_BT601NARROW =10, + V2D_CSC_MODE_BT601NARROW_2_BT709WIDE =11, + V2D_CSC_MODE_BT601NARROW_2_BT709NARROW =12, + V2D_CSC_MODE_BT601NARROW_2_BT601WIDE =13, + V2D_CSC_MODE_BT709WIDE_2_BT601WIDE =14, + V2D_CSC_MODE_BT709WIDE_2_BT601NARROW =15, + V2D_CSC_MODE_BT709WIDE_2_BT709NARROW =16, + V2D_CSC_MODE_BT709NARROW_2_BT601WIDE =17, + V2D_CSC_MODE_BT709NARROW_2_BT601NARROW =18, + V2D_CSC_MODE_BT709NARROW_2_BT709WIDE =19, + V2D_CSC_MODE_RGB_2_GREY =20, + V2D_CSC_MODE_RGB_2_RGB =21, + V2D_CSC_MODE_BUTT =22, +} V2D_CSC_MODE_E; + +typedef enum SPACEMIT_FBC_DECODER_MODE_E +{ + FBC_DECODER_MODE_SCAN_LINE =0, + FBC_DECODER_MODE_LDC_Y =1, + FBC_DECODER_MODE_LDC_UV =2, + FBC_DECODER_MODE_H264_32x16 =3, + FBC_DECODER_MODE_H265_32x32 =4, + FBC_DECODER_MODE_BUTT =5, +} FBC_DECODER_MODE_E; + +typedef enum SPACEMIT_FBC_DECODER_FORMAT_E +{ + FBC_DECODER_FORMAT_NV12 =0, + FBC_DECODER_FORMAT_RGB888 =1, + FBC_DECODER_FORMAT_ARGB8888 =2, + FBC_DECODER_FORMAT_RGB565 =3, + FBC_DECODER_FORMAT_BUTT =4, +} FBC_DECODER_FORMAT_E; + +typedef struct +{ + uint16_t x; /* left */ + uint16_t y; /* top */ + uint16_t w; /* crop width */ + uint16_t h; /* crop height */ +} V2D_AREA_S; + +typedef struct SPACEMIT_V2D_FILLCOLOR_S +{ + uint32_t colorvalue; + V2D_COLOR_FORMAT_E format; +} V2D_FILLCOLOR_S; + +typedef struct SPACEMIT_V2D_BACKGROUND_S +{ + V2D_FILLCOLOR_S fillcolor; + bool enable; +} V2D_BACKGROUND_S; + +typedef struct SPACEMIT_V2D_SOLIDCOLOR_S +{ + V2D_FILLCOLOR_S fillcolor; + bool enable; +} V2D_SOLIDCOLOR_S; + +typedef struct SPACEMIT_V2D_PALETTE_S +{ + uint8_t palVal[1024]; + int len; +} V2D_PALETTE_S; + +typedef struct SPACEMIT_FBC_DECODER_S +{ + int fd; + uint32_t headerAddr_h; + uint32_t headerAddr_l; + uint16_t bboxLeft; + uint16_t bboxRight; + uint16_t bboxTop; + uint16_t bboxBottom; + bool rgb_pack_en; + bool is_split; + FBC_DECODER_MODE_E enFbcdecMode; + FBC_DECODER_FORMAT_E enFbcdecFmt; +} FBC_DECODER_S; + +typedef FBC_DECODER_FORMAT_E FBC_ENCODER_FORMAT_E; +typedef struct SPACEMIT_FBC_ENCODER_S +{ + int fd; + int offset; + uint32_t headerAddr_h; + uint32_t headerAddr_l; + uint32_t payloadAddr_h; + uint32_t payloadAddr_l; + uint16_t bboxLeft; + uint16_t bboxRight; + uint16_t bboxTop; + uint16_t bboxBottom; + bool is_split; + FBC_ENCODER_FORMAT_E enFbcencFmt; +} FBC_ENCODER_S; + +typedef struct SPACEMIT_V2D_SURFACE_S +{ + struct + { + bool fbc_enable; + int fd; + int offset; + uint32_t phyaddr_y_l; + uint32_t phyaddr_y_h; + uint32_t phyaddr_uv_l; + uint32_t phyaddr_uv_h; + uint16_t w; + uint16_t h; + uint16_t stride; + V2D_COLOR_FORMAT_E format; + }; + union + { + FBC_DECODER_S fbcDecInfo; + FBC_ENCODER_S fbcEncInfo; + }; + V2D_SOLIDCOLOR_S solidcolor; +} V2D_SURFACE_S; + +typedef struct +{ + V2D_BLEND_MODE_E srcColorFactor; + V2D_BLEND_MODE_E dstColorFactor; + V2D_BLEND_MODE_E srcAlphaFactor; + V2D_BLEND_MODE_E dstAlphaFactor; +} V2D_BLEND_FACTOR_S; + +typedef struct +{ + V2D_ROP2_MODE_E colorRop2Code; + V2D_ROP2_MODE_E alphaRop2Code; +} V2D_ROP2_CODE_S; + +typedef struct +{ + V2D_BLENDALPHA_SOURCE_E blend_alpha_source; + V2D_BLEND_PRE_ALPHA_FUNC_E blend_pre_alpha_func; + uint8_t global_alpha; + union + { + V2D_BLEND_FACTOR_S stBlendFactor; + V2D_ROP2_CODE_S stRop2Code; + }; + V2D_AREA_S blend_area; +} V2D_BLEND_LAYER_CONF_S; + +typedef struct +{ + V2D_BLENDCMD_E blend_cmd; + V2D_BACKGROUND_S bgcolor; + V2D_MASKCMD_E mask_cmd; + V2D_AREA_S blend_mask_area; + V2D_BLEND_LAYER_CONF_S blendlayer[V2D_INPUT_LAYER_NUM]; +} V2D_BLEND_CONF_S; + +typedef struct +{ + V2D_SURFACE_S layer0; + V2D_SURFACE_S layer1; + V2D_SURFACE_S mask; + V2D_SURFACE_S dst; + V2D_AREA_S l0_rect; + V2D_AREA_S l1_rect; + V2D_AREA_S mask_rect; + V2D_AREA_S dst_rect; + V2D_BLEND_CONF_S blendconf; + V2D_ROTATE_ANGLE_E l0_rt; + V2D_ROTATE_ANGLE_E l1_rt; + V2D_CSC_MODE_E l0_csc; + V2D_CSC_MODE_E l1_csc; + V2D_DITHER_E dither; + V2D_PALETTE_S palette; +} V2D_PARAM_S; + +typedef struct +{ + V2D_PARAM_S param; + int32_t acquireFencefd; + int32_t completeFencefd; +} V2D_SUBMIT_TASK_S; + +typedef struct +{ + uint32_t size; + uint64_t phys_addr; + void *virt_addr; +} V2D_BUFFER_S; + +#define V2D_IOC_MAGIC 'V' +#define V2D_SUBMIT _IOWR(V2D_IOC_MAGIC, 0, V2D_SUBMIT_TASK_S) +#define V2D_ALLOC_BUFFER _IOWR(V2D_IOC_MAGIC, 1, V2D_BUFFER_S) +#define V2D_FREE_BUFFER _IOW(V2D_IOC_MAGIC, 2, V2D_BUFFER_S) +#define V2D_RESET _IO(V2D_IOC_MAGIC, 3) + +#endif /* __SPACEMIT_V2D_H__ */ diff --git a/bsp/spacemit/dm/input/SConscript b/bsp/spacemit/dm/input/SConscript new file mode 100644 index 000000000000..3d15055d62d2 --- /dev/null +++ b/bsp/spacemit/dm/input/SConscript @@ -0,0 +1,13 @@ +import os +from building import * + +cwd = GetCurrentDir() +objs = [] +list = os.listdir(cwd) + +for d in list: + path = os.path.join(cwd, d) + if os.path.isfile(os.path.join(path, 'SConscript')): + objs = objs + SConscript(os.path.join(d, 'SConscript')) + +Return('objs') diff --git a/bsp/spacemit/dm/input/misc/Kconfig b/bsp/spacemit/dm/input/misc/Kconfig new file mode 100644 index 000000000000..64e5bd720f68 --- /dev/null +++ b/bsp/spacemit/dm/input/misc/Kconfig @@ -0,0 +1,5 @@ +config RT_INPUT_MISC_PWRKEY_SPACEMIT_PMIC + bool "Spacemit PMIC power key support" + depends on RT_INPUT_MISC + depends on RT_MFD_SPACEMIT_PMIC + default n diff --git a/bsp/spacemit/dm/input/misc/SConscript b/bsp/spacemit/dm/input/misc/SConscript new file mode 100644 index 000000000000..c1f5f17ab6e9 --- /dev/null +++ b/bsp/spacemit/dm/input/misc/SConscript @@ -0,0 +1,13 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../../include'] + +if GetDepend(['RT_INPUT_MISC_PWRKEY_SPACEMIT_PMIC']): + src += ['pwrkey-spacemit-pmic.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/input/misc/pwrkey-spacemit-pmic.c b/bsp/spacemit/dm/input/misc/pwrkey-spacemit-pmic.c new file mode 100644 index 000000000000..28ac2d63bae1 --- /dev/null +++ b/bsp/spacemit/dm/input/misc/pwrkey-spacemit-pmic.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#define __SPACEMIT_PWRKEY_INTERNAL +#include + +struct spacemit_pmic_pwrkey +{ + struct rt_input_device parent; + + int fall_irq, rise_irq; + int s_key_irq, l_key_irq; +}; + +static void spacemit_pmic_pwrkey_fall_irq(int irqno, void *param) +{ + struct spacemit_pmic_pwrkey *pwr = param; + + rt_interrupt_enter(); + + rt_input_report_key(&pwr->parent, KEY_POWER, 1); + rt_input_sync(&pwr->parent); + + rt_interrupt_leave(); +} + +static void spacemit_pmic_pwrkey_rise_irq(int irqno, void *param) +{ + struct spacemit_pmic_pwrkey *pwr = param; + + rt_interrupt_enter(); + + rt_input_report_key(&pwr->parent, KEY_POWER, 0); + rt_input_sync(&pwr->parent); + + rt_interrupt_leave(); +} + +static void spacemit_pmic_pwrkey_skey_irq(int irqno, void *param) +{ + /* Do nothing by now */ +} + +static void spacemit_pmic_pwrkey_lkey_irq(int irqno, void *param) +{ + /* Do nothing by now */ +} + +static rt_err_t spacemit_pmic_pwrkey_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct spacemit_pmic_pwrkey *pwr = rt_calloc(1, sizeof(*pwr)); + + if (!pwr) + { + return -RT_ENOMEM; + } + + if ((pwr->rise_irq = rt_dm_dev_get_irq(dev, 0)) < 0) + { + err = pwr->rise_irq; + goto _fail; + } + + if ((pwr->fall_irq = rt_dm_dev_get_irq(dev, 1)) < 0) + { + err = pwr->fall_irq; + goto _fail; + } + + if ((pwr->s_key_irq = rt_dm_dev_get_irq(dev, 2)) < 0) + { + err = pwr->s_key_irq; + goto _fail; + } + + if ((pwr->l_key_irq = rt_dm_dev_get_irq(dev, 3)) < 0) + { + err = pwr->l_key_irq; + goto _fail; + } + + rt_input_set_capability(&pwr->parent, EV_KEY, KEY_POWER); + + if ((err = rt_input_device_register(&pwr->parent))) + { + goto _fail; + } + + dev->user_data = pwr; + + rt_hw_interrupt_install(pwr->fall_irq, spacemit_pmic_pwrkey_fall_irq, pwr, "pwrkey-pmic-fall"); + rt_hw_interrupt_umask(pwr->fall_irq); + + rt_hw_interrupt_install(pwr->rise_irq, spacemit_pmic_pwrkey_rise_irq, pwr, "pwrkey-pmic-rise"); + rt_hw_interrupt_umask(pwr->rise_irq); + + rt_hw_interrupt_install(pwr->s_key_irq, spacemit_pmic_pwrkey_skey_irq, pwr, "pwrkey-pmic-skey"); + rt_hw_interrupt_umask(pwr->s_key_irq); + + rt_hw_interrupt_install(pwr->l_key_irq, spacemit_pmic_pwrkey_lkey_irq, pwr, "pwrkey-pmic-lkey"); + rt_hw_interrupt_umask(pwr->l_key_irq); + + return RT_EOK; + +_fail: + rt_free(pwr); + + return err; +} + +static rt_err_t spacemit_pmic_pwrkey_remove(struct rt_platform_device *pdev) +{ + struct spacemit_pmic_pwrkey *pwr = pdev->parent.user_data; + + rt_hw_interrupt_mask(pwr->fall_irq); + rt_pic_detach_irq(pwr->fall_irq, pwr); + + rt_hw_interrupt_mask(pwr->rise_irq); + rt_pic_detach_irq(pwr->rise_irq, pwr); + + rt_hw_interrupt_mask(pwr->s_key_irq); + rt_pic_detach_irq(pwr->s_key_irq, pwr); + + rt_hw_interrupt_mask(pwr->l_key_irq); + rt_pic_detach_irq(pwr->l_key_irq, pwr); + + rt_input_device_unregister(&pwr->parent); + + rt_free(pwr); + + return RT_EOK; +} + +static const struct rt_ofw_node_id spacemit_pmic_pwrkey_ofw_ids[] = +{ + { .compatible = "pmic,pwrkey,spm8821" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_pmic_pwrkey_driver = +{ + .name = "spacemit-pmic-pwrkey", + .ids = spacemit_pmic_pwrkey_ofw_ids, + + .probe = spacemit_pmic_pwrkey_probe, + .remove = spacemit_pmic_pwrkey_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(spacemit_pmic_pwrkey_driver); diff --git a/bsp/spacemit/dm/mailbox/Kconfig b/bsp/spacemit/dm/mailbox/Kconfig new file mode 100644 index 000000000000..b4f54b2dee3e --- /dev/null +++ b/bsp/spacemit/dm/mailbox/Kconfig @@ -0,0 +1,3 @@ +config RT_MBOX_K1X + bool "Spacemit K1pro Mailbox Support" + default n diff --git a/bsp/spacemit/dm/mailbox/SConscript b/bsp/spacemit/dm/mailbox/SConscript new file mode 100644 index 000000000000..176d261ed8ac --- /dev/null +++ b/bsp/spacemit/dm/mailbox/SConscript @@ -0,0 +1,12 @@ +from building import * + +cwd = GetCurrentDir() +src = [] +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_MBOX_K1X']): + src += ['mailbox-k1x.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/mailbox/mailbox-k1x.c b/bsp/spacemit/dm/mailbox/mailbox-k1x.c new file mode 100644 index 000000000000..133908e9f064 --- /dev/null +++ b/bsp/spacemit/dm/mailbox/mailbox-k1x.c @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include + +#include + +#define DBG_TAG "mailbox.spacemit" +#define DBG_LVL DBG_INFO +#include + +#define SPACEMIT_NUM_CHANNELS 4 +#define SPACEMIT_TX_ACK_OFFSET 4 + +#define MBOX_REG_IPC_DW 0x00 +#define MBOX_REG_IPC_WDR 0x04 +#define MBOX_REG_ISRW 0x08 +#define MBOX_REG_ICR 0x0C +#define MBOX_REG_IIR 0x10 +#define MBOX_REG_RDR 0x14 + +struct spacemit_mailbox +{ + struct rt_mbox_controller parent; + + int irq; + void *regs; + rt_bool_t clk_enabled; + struct rt_clk *clk; + struct rt_reset_control *rstc; +}; + +#define raw_to_spacemit_mailbox(raw) rt_container_of(raw, struct spacemit_mailbox, parent) + +static rt_err_t spacemit_mailbox_request(struct rt_mbox_chan *chan) +{ + return RT_EOK; +} + +static void spacemit_mailbox_release(struct rt_mbox_chan *chan) +{ + struct spacemit_mailbox *sp_mbox = raw_to_spacemit_mailbox(chan->ctrl); + + HWREG32(sp_mbox->regs + MBOX_REG_ICR) = + RT_BIT(chan - sp_mbox->parent.chans); +} + +static rt_err_t spacemit_mailbox_send(struct rt_mbox_chan *chan, const void *data) +{ + struct spacemit_mailbox *sp_mbox = raw_to_spacemit_mailbox(chan->ctrl); + + HWREG32(sp_mbox->regs + MBOX_REG_ISRW) = + RT_BIT(chan - sp_mbox->parent.chans); + + return RT_EOK; +} + +static rt_bool_t spacemit_mailbox_peek(struct rt_mbox_chan *chan) +{ + struct spacemit_mailbox *sp_mbox = raw_to_spacemit_mailbox(chan->ctrl); + + return !!(HWREG32(sp_mbox->regs + MBOX_REG_RDR) & + RT_BIT(chan - sp_mbox->parent.chans)); +} + +static const struct rt_mbox_controller_ops spacemit_mailbox_ops = +{ + .request = spacemit_mailbox_request, + .release = spacemit_mailbox_release, + .send = spacemit_mailbox_send, + .peek = spacemit_mailbox_peek, +}; + +static void spacemit_mailbox_isr(int irqno, void *param) +{ + rt_uint32_t status, msg = 0; + struct rt_mbox_chan *chan; + struct spacemit_mailbox *sp_mbox = param; + + HWREG32(sp_mbox->regs + MBOX_REG_IIR) = 0; + + status = HWREG32(sp_mbox->regs + MBOX_REG_IIR); + + if (!(status & 0xff)) + { + return; + } + + for (int i = SPACEMIT_TX_ACK_OFFSET; i < SPACEMIT_NUM_CHANNELS + SPACEMIT_TX_ACK_OFFSET; ++i) + { + chan = &sp_mbox->parent.chans[i - SPACEMIT_TX_ACK_OFFSET]; + + if (!(status & RT_BIT(i))) + { + continue; + } + + /* Clear the irq pending */ + HWREG32(sp_mbox->regs + MBOX_REG_ICR) = 1 << i; + + rt_mbox_send_done(chan, 0); + } + + for (int i = 0; i < SPACEMIT_NUM_CHANNELS; ++i) + { + chan = &sp_mbox->parent.chans[i]; + + if (!(status & RT_BIT(i))) + { + continue; + } + + rt_mbox_recv(chan, &msg); + + /* Clear the irq pending */ + HWREG32(sp_mbox->regs + MBOX_REG_ICR) = RT_BIT(i); + + /* Then send an ack */ + HWREG32(sp_mbox->regs + MBOX_REG_ISRW) = RT_BIT(i + SPACEMIT_TX_ACK_OFFSET); + } +} + +static void spacemit_mailbox_free_resource(struct spacemit_mailbox *sp_mbox) +{ + if (sp_mbox->regs) + { + rt_iounmap(sp_mbox->regs); + } + + if (!rt_is_err_or_null(sp_mbox->clk)) + { + if (sp_mbox->clk_enabled) + { + rt_clk_disable_unprepare(sp_mbox->clk); + } + rt_clk_put(sp_mbox->clk); + } + + if (!rt_is_err_or_null(sp_mbox->rstc)) + { + rt_reset_control_put(sp_mbox->rstc); + } + + rt_free(sp_mbox); +} + +static rt_err_t spacemit_mailbox_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct spacemit_mailbox *sp_mbox = rt_calloc(1, sizeof(*sp_mbox)); + + if (!sp_mbox) + { + return -RT_ENOMEM; + } + + sp_mbox->regs = rt_dm_dev_iomap(dev, 0); + + if (!sp_mbox->regs) + { + err = -RT_EIO; + goto _fail; + } + + sp_mbox->clk = rt_clk_get_by_name(dev, "core"); + + if (rt_is_err(sp_mbox->clk)) + { + err = rt_ptr_err(sp_mbox->clk); + goto _fail; + } + + if ((err = rt_clk_prepare_enable(sp_mbox->clk))) + { + goto _fail; + } + sp_mbox->clk_enabled = RT_TRUE; + + sp_mbox->rstc = rt_reset_control_get_by_name(dev, "core_reset"); + + if (rt_is_err(sp_mbox->rstc)) + { + err = rt_ptr_err(sp_mbox->rstc); + goto _fail; + } + + if ((err = rt_reset_control_deassert(sp_mbox->rstc))) + { + goto _fail; + } + + sp_mbox->irq = rt_dm_dev_get_irq(dev, 0); + + if (sp_mbox->irq < 0) + { + err = sp_mbox->irq; + goto _fail; + } + + rt_hw_interrupt_install(sp_mbox->irq, spacemit_mailbox_isr, sp_mbox, "sp_mbox"); + rt_hw_interrupt_umask(sp_mbox->irq); + + dev->user_data = sp_mbox; + + sp_mbox->parent.dev = dev; + sp_mbox->parent.num_chans = SPACEMIT_NUM_CHANNELS; + sp_mbox->parent.ops = &spacemit_mailbox_ops; + + if ((err = rt_mbox_controller_register(&sp_mbox->parent))) + { + goto _free_irq; + } + + return RT_EOK; + +_free_irq: + rt_hw_interrupt_mask(sp_mbox->irq); + rt_pic_detach_irq(sp_mbox->irq, sp_mbox); + +_fail: + spacemit_mailbox_free_resource(sp_mbox); + + return err; +} + +static rt_err_t spacemit_mailbox_remove(struct rt_platform_device *pdev) +{ + struct spacemit_mailbox *sp_mbox = pdev->parent.user_data; + + rt_hw_interrupt_mask(sp_mbox->irq); + rt_pic_detach_irq(sp_mbox->irq, sp_mbox); + + rt_mbox_controller_unregister(&sp_mbox->parent); + + spacemit_mailbox_free_resource(sp_mbox); + + return RT_EOK; +} + +static const struct rt_ofw_node_id spacemit_mailbox_ofw_ids[] = +{ + { .compatible = "spacemit,k1-x-mailbox", }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_mailbox_driver = +{ + .name = "mailbox-spacemit", + .ids = spacemit_mailbox_ofw_ids, + + .probe = spacemit_mailbox_probe, + .remove = spacemit_mailbox_remove, +}; + +static int spacemit_mailbox_drv_register(void) +{ + rt_platform_driver_register(&spacemit_mailbox_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(spacemit_mailbox_drv_register); diff --git a/bsp/spacemit/dm/mfd/Kconfig b/bsp/spacemit/dm/mfd/Kconfig new file mode 100644 index 000000000000..017cd0cad80b --- /dev/null +++ b/bsp/spacemit/dm/mfd/Kconfig @@ -0,0 +1,7 @@ +config RT_MFD_SPACEMIT_PMIC + bool "Spacemit Power Management Chip" + depends on RT_USING_PIC + depends on RT_USING_I2C + depends on RT_USING_OFW + select RT_MFD_SYSCON + default y diff --git a/bsp/spacemit/dm/mfd/SConscript b/bsp/spacemit/dm/mfd/SConscript new file mode 100644 index 000000000000..e188ee121125 --- /dev/null +++ b/bsp/spacemit/dm/mfd/SConscript @@ -0,0 +1,12 @@ +from building import * + +cwd = GetCurrentDir() +src = [] +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_MFD_SPACEMIT_PMIC']): + src += ['spacemit-pmic.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/mfd/spacemit-pmic.c b/bsp/spacemit/dm/mfd/spacemit-pmic.c new file mode 100644 index 000000000000..3f042e39a856 --- /dev/null +++ b/bsp/spacemit/dm/mfd/spacemit-pmic.c @@ -0,0 +1,763 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include + +#define DBG_TAG "mfd.spacemit-pmic" +#define DBG_LVL DBG_INFO +#include + +#include +#define __SPACEMIT_PMIC_INTERNAL +#include + +#ifdef RT_USING_FINSH +#include +#endif + +struct restart_config_info +{ + const char *cmd; + uint32_t value; +}; + +static const struct restart_config_info config_info[] = +{ + /* Enter uboot fastboot mode after restart */ + { "fastboot", 1 }, + /* Enter uboot shell after restart */ + { "uboot", 2 }, +}; + +static rt_err_t spacemit_pmic_reboot(struct rt_device *dev, char *cmd) +{ + struct spacemit_pmic *pmic = dev->user_data; + const struct spacemit_pmic_mfd_data *mfd_data = pmic->mfd_data; + + if (cmd) + { + for (int i = 0; i < RT_ARRAY_SIZE(config_info); ++i) + { + if (!rt_strcmp(cmd, config_info[i].cmd)) + { + spacemit_pmic_update_bits(pmic, + mfd_data->non_reset.reg, + mfd_data->non_reset.bit, + config_info[i].value); + break; + } + } + } + + if (spacemit_pmic_update_bits(pmic, + mfd_data->reboot.reg, + mfd_data->reboot.bit, + mfd_data->reboot.bit)) + { + LOG_E("Failed to %s device", "reboot"); + } + + return RT_EOK; +} + +static rt_err_t spacemit_pmic_shutdown(struct rt_device *dev) +{ + struct spacemit_pmic *pmic = dev->user_data; + const struct spacemit_pmic_mfd_data *mfd_data = pmic->mfd_data; + + if (spacemit_pmic_update_bits(pmic, + mfd_data->shutdown.reg, + mfd_data->shutdown.bit, + mfd_data->shutdown.bit)) + { + LOG_E("Failed to %s device", "shutdown"); + } + + return RT_EOK; +} + +static void spacemit_pmic_irq_mask(struct rt_pic_irq *pirq) +{ + rt_err_t err; + unsigned value; + struct spacemit_pmic_irqchip *irqchip = raw_to_spacemit_pmic_irqchip(pirq->pic); + const struct spacemit_pmic_irq_map *irq_map = &irqchip->irqs_map[pirq->hwirq]; + + value = irqchip->mask_base + (irq_map->reg_offset / irqchip->reg_stride); + + err = spacemit_pmic_update_bits(irqchip->pmic, value, irq_map->mask, + irqchip->mask_unmask_non_inverted ? 0 : irq_map->mask); + + if (err) + { + LOG_E("Mask PMIC IRQ %d failed: %s", pirq->hwirq, rt_strerror(err)); + } +} + +static void spacemit_pmic_irq_unmask(struct rt_pic_irq *pirq) +{ + rt_err_t err; + unsigned value; + struct spacemit_pmic_irqchip *irqchip = raw_to_spacemit_pmic_irqchip(pirq->pic); + const struct spacemit_pmic_irq_map *irq_map = &irqchip->irqs_map[pirq->hwirq]; + + value = irqchip->mask_base + (irq_map->reg_offset / irqchip->reg_stride); + + err = spacemit_pmic_update_bits(irqchip->pmic, value, irq_map->mask, + irqchip->mask_unmask_non_inverted ? irq_map->mask : 0); + + if (err) + { + LOG_E("Unmask PMIC IRQ %d failed: %s", pirq->hwirq, rt_strerror(err)); + } +} + +static int spacemit_pmic_irq_map(struct rt_pic *pic, int hwirq, rt_uint32_t mode) +{ + int irq = -1; + struct rt_pic_irq *pirq = rt_pic_find_irq(pic, hwirq); + + if (pirq) + { + struct spacemit_pmic_irqchip *irqchip = raw_to_spacemit_pmic_irqchip(pic); + + irq = rt_pic_config_irq(pic, hwirq, hwirq); + pirq->mode = mode; + rt_pic_cascade(pirq, irqchip->pmic->irq); + } + + return irq; +} + +static rt_err_t spacemit_pmic_irq_parse(struct rt_pic *pic, struct rt_ofw_cell_args *args, struct rt_pic_irq *out_pirq) +{ + struct spacemit_pmic_irqchip *irqchip = raw_to_spacemit_pmic_irqchip(pic); + + if (args->args_count != 1) + { + return -RT_EINVAL; + } + + out_pirq->mode = rt_pic_irq_get_triger_mode(irqchip->pmic->irq); + out_pirq->hwirq = args->args[0]; + + return RT_EOK; +} + +const static struct rt_pic_ops spacemit_pmic_irq_ops = +{ + .name = "Spacemit-PMIC", + .irq_mask = spacemit_pmic_irq_mask, + .irq_unmask = spacemit_pmic_irq_unmask, + .irq_map = spacemit_pmic_irq_map, + .irq_parse = spacemit_pmic_irq_parse, +}; + +static rt_uint32_t spacemit_pmic_irq_valid_mask(struct spacemit_pmic_irqchip *irqchip, + int reg_index) +{ + rt_uint32_t mask = 0; + + for (int i = 0; i < irqchip->irqs_nr; ++i) + { + if (irqchip->irqs_map[i].reg_offset / irqchip->reg_stride == reg_index) + { + mask |= irqchip->irqs_map[i].mask; + } + } + + return mask; +} + +static void spacemit_pmic_thread_isr(void *param) +{ + rt_bool_t parent_rearmed; + rt_uint32_t enabled, *status; + rt_uint16_t base, reg; + struct rt_pic_irq *pirq; + struct spacemit_pmic *pmic; + struct spacemit_pmic_irqchip *irqchip = param; + + pmic = irqchip->pmic; + status = irqchip->irq_status; + + while (RT_TRUE) + { + if (rt_sem_take(&irqchip->irq_sem, RT_WAITING_FOREVER)) + { + continue; + } + + parent_rearmed = RT_FALSE; + ++irqchip->worker_count; + + base = irqchip->status_base; + rt_memset(status, 0, sizeof(*status) * irqchip->num_regs); + + for (int i = 0; i < irqchip->num_regs; ++i) + { + reg = base + i * irqchip->reg_stride; + status[i] = spacemit_pmic_read(pmic, reg); + + if ((rt_err_t)status[i] < 0) + { + LOG_E("Read IRQ status failed error = %s", rt_strerror(status[i])); + + goto _end; + } + + enabled = spacemit_pmic_read(pmic, + irqchip->mask_base + i * irqchip->reg_stride); + + if ((rt_err_t)enabled < 0) + { + LOG_E("Read IRQ mask failed error = %s", rt_strerror(enabled)); + + goto _end; + } + + if (irqchip->mask_unmask_non_inverted) + { + status[i] &= enabled; + } + else + { + status[i] &= ~enabled; + } + } + + base = irqchip->ack_base; + + for (int i = 0; i < irqchip->num_regs; ++i) + { + rt_err_t err; + + reg = base + i * irqchip->reg_stride; + err = spacemit_pmic_write(pmic, reg, status[i]); + + if (err) + { + LOG_E("ACK IRQ failed error = %s", rt_strerror(err)); + + goto _end; + } + } + + /* The PMIC line is clear after ACK; rearm before child handlers can schedule. */ + rt_hw_interrupt_umask(pmic->irq); + ++irqchip->rearm_count; + parent_rearmed = RT_TRUE; + + for (int i = 0; i < irqchip->irqs_nr; ++i) + { + base = irqchip->irqs_map[i].reg_offset / irqchip->reg_stride; + + if (status[base] & irqchip->irqs_map[i].mask) + { + pirq = rt_pic_find_irq(&irqchip->parent, i); + + if (pirq && pirq->pic) + { + rt_pic_handle_isr(pirq); + } + } + } + _end: + if (!parent_rearmed) + { + rt_hw_interrupt_umask(pmic->irq); + ++irqchip->rearm_count; + } + } +} + +static void spacemit_pmic_isr(int irqno, void *param) +{ + struct spacemit_pmic_irqchip *irqchip = param; + + ++irqchip->hard_irq_count; + rt_hw_interrupt_mask(irqchip->pmic->irq); + + rt_sem_release(&irqchip->irq_sem); +} + +#define spacemit_pmic_to_i2c_client(pmic) rt_container_of((pmic)->dev, struct rt_i2c_client, parent) + +static unsigned spacemit_pmic_i2c_read_unlocked(struct spacemit_pmic *pmic, unsigned reg) +{ + rt_uint8_t data = 0; + rt_uint8_t send_buf[2]; + struct rt_i2c_msg msg[2]; + struct rt_i2c_client *client = spacemit_pmic_to_i2c_client(pmic); + + send_buf[0] = (reg & 0xff); + + msg[0].addr = client->client_addr + pmic->addr_offset; + msg[0].flags = RT_I2C_WR; + msg[0].len = 1; + msg[0].buf = send_buf; + + msg[1].addr = client->client_addr + pmic->addr_offset; + msg[1].flags = RT_I2C_RD; + msg[1].len = 1; + msg[1].buf = &data; + + if (rt_i2c_transfer(client->bus, msg, 2) == 2) + { + return data; + } + else + { + return (unsigned)-RT_ERROR; + } +} + +static rt_err_t spacemit_pmic_i2c_write_unlocked(struct spacemit_pmic *pmic, + unsigned reg, unsigned data) +{ + rt_uint8_t send_buf[2]; + struct rt_i2c_msg msg; + struct rt_i2c_client *client = spacemit_pmic_to_i2c_client(pmic); + + send_buf[0] = reg & 0xff; + send_buf[1] = data; + + msg.addr = client->client_addr + pmic->addr_offset; + msg.flags = RT_I2C_WR; + msg.len = 2; + msg.buf = send_buf; + + if (rt_i2c_transfer(client->bus, &msg, 1) == 1) + { + return RT_EOK; + } + else + { + return -RT_ERROR; + } +} + +static unsigned spacemit_pmic_i2c_read(struct spacemit_pmic *pmic, unsigned reg) +{ + unsigned value; + rt_err_t err = rt_mutex_take(pmic->io_lock, RT_WAITING_FOREVER); + + if (err) + { + return (unsigned)err; + } + + value = spacemit_pmic_i2c_read_unlocked(pmic, reg); + rt_mutex_release(pmic->io_lock); + + return value; +} + +static rt_err_t spacemit_pmic_i2c_write(struct spacemit_pmic *pmic, + unsigned reg, unsigned data) +{ + rt_err_t err = rt_mutex_take(pmic->io_lock, RT_WAITING_FOREVER); + + if (err) + { + return err; + } + + err = spacemit_pmic_i2c_write_unlocked(pmic, reg, data); + rt_mutex_release(pmic->io_lock); + + return err; +} + +static rt_err_t spacemit_pmic_i2c_write_bit(struct spacemit_pmic *pmic, + unsigned reg, unsigned mask, unsigned data) +{ + rt_err_t err; + rt_int32_t val; + + if ((err = rt_mutex_take(pmic->io_lock, RT_WAITING_FOREVER))) + { + return err; + } + + val = (rt_int32_t)spacemit_pmic_i2c_read_unlocked(pmic, reg); + + if (val < 0) + { + err = val; + goto _out; + } + + if (data) + { + val |= mask; + } + else + { + val &= ~mask; + } + + err = spacemit_pmic_i2c_write_unlocked(pmic, reg, val); + +_out: + rt_mutex_release(pmic->io_lock); + + return err; +} + +static rt_err_t spacemit_pmic_i2c_update_bits(struct spacemit_pmic *pmic, unsigned reg, + unsigned mask, unsigned data) +{ + rt_err_t err; + rt_int32_t old; + rt_uint32_t tmp; + + if ((err = rt_mutex_take(pmic->io_lock, RT_WAITING_FOREVER))) + { + return err; + } + + old = (rt_int32_t)spacemit_pmic_i2c_read_unlocked(pmic, reg); + + if (old < 0) + { + err = old; + goto _out; + } + + tmp = old & ~mask; + tmp |= (data & mask); + + err = spacemit_pmic_i2c_write_unlocked(pmic, reg, tmp); + +_out: + rt_mutex_release(pmic->io_lock); + + return err; +} + +static rt_err_t create_spacemit_pmic_platform_device(rt_bus_t platform_bus, + struct spacemit_pmic *pmic, const char *name, void *ofw_node) +{ + rt_err_t err; + struct rt_platform_device *pdev = rt_platform_device_alloc(name); + + if (!pdev) + { + return -RT_ENOMEM; + } + + pdev->parent.ofw_node = ofw_node; + pdev->priv = pmic; + + err = rt_bus_add_device(platform_bus, &pdev->parent); + + if (err && err != -RT_ENOSYS) + { + LOG_E("Add %s - %s error = %s", "SPACEMIT-PMIC", name, rt_strerror(err)); + } + + return err; +} + +static rt_err_t spacemit_pmic_ofw_bind_irq(struct spacemit_pmic_irqchip *irqchip, + struct rt_ofw_node *dev_np, struct rt_ofw_node *np, + const struct spacemit_pmic_mfd_endpoint *ep) +{ + /* + * ic: spacemit-pmic-interrupt-controller { + * #interrupt-cells = <1>; + * + * spacemit-pmic-endpoint0 { + * interrupts-extended = <&ic 0>; + * } + * + * spacemit-pmic-endpoint1 { + * interrupts-extended = <&ic 1>, <&ic 2>; + * } + * } + */ + rt_err_t err; + fdt32_t *values; + rt_size_t irq_list_size; + static fdt32_t irq_cell; + static struct rt_ofw_node *ic_np = RT_NULL; + + if (!ic_np) + { + ic_np = rt_ofw_append_child(dev_np, "spacemit-pmic-interrupt-controller"); + + if (!ic_np) + { + return -RT_ENOSYS; + } + + irq_cell = cpu_to_fdt32(1); + err = rt_ofw_append_prop(ic_np, "#interrupt-cells", sizeof(fdt32_t), &irq_cell); + + if (err) + { + return err; + } + + rt_ofw_data(ic_np) = &irqchip->parent; + } + + irq_list_size = sizeof(fdt32_t) * 2 * ep->irqs_nr; + values = rt_malloc(irq_list_size); + + if (!values) + { + return -RT_ENOMEM; + } + + for (int i = 0; i < ep->irqs_nr; ++i) + { + values[i * 2] = cpu_to_fdt32(ic_np->phandle); + values[i * 2 + 1] = cpu_to_fdt32(ep->irqs_list[i]); + } + + if ((err = rt_ofw_append_prop(np, "interrupts-extended", irq_list_size, values))) + { + rt_free(values); + } + + return err; +} + +static rt_err_t spacemit_pmic_i2c_probe(struct rt_i2c_client *client) +{ + rt_err_t err; + rt_bus_t platform_bus; + struct rt_ofw_node *np, *dev_np; + struct rt_device *dev = &client->parent; + struct spacemit_pmic *pmic; + struct spacemit_pmic_mfd_endpoint *pmic_ep; + const struct spacemit_pmic_mfd_data *mfd_data = rt_i2c_client_id_data(client); + + platform_bus = rt_bus_find_by_name("platform"); + + if (!platform_bus) + { + return -RT_EIO; + } + + if (!(pmic = rt_calloc(1, sizeof(*pmic)))) + { + return -RT_ENOMEM; + } + + if (!(pmic->io_lock = rt_mutex_create("pmic-io", RT_IPC_FLAG_PRIO))) + { + rt_free(pmic); + return -RT_ENOMEM; + } + + pmic->dev = dev; + pmic->mfd_data = mfd_data; + pmic->read = spacemit_pmic_i2c_read; + pmic->write = spacemit_pmic_i2c_write; + pmic->write_bit = spacemit_pmic_i2c_write_bit; + pmic->update_bits = spacemit_pmic_i2c_update_bits; + + if (mfd_data->irqchip) + { + struct spacemit_pmic_irqchip *irqchip = mfd_data->irqchip; + + if ((pmic->irq = rt_dm_dev_get_irq(dev, 0)) < 0) + { + err = pmic->irq; + goto _fail; + } + + irqchip->pmic = pmic; + irqchip->parent.priv_data = irqchip; + irqchip->parent.ops = &spacemit_pmic_irq_ops; + + if ((err = rt_pic_linear_irq(&irqchip->parent, irqchip->irqs_nr))) + { + LOG_E("Init %s IRQ chip failed error = %s", "SPACEMIT-PMIC", rt_strerror(err)); + goto _fail; + } + + /* Match regmap-irq: mask and acknowledge all defined interrupts. */ + for (int i = 0; i < irqchip->num_regs; ++i) + { + rt_uint32_t status, valid_mask; + + valid_mask = spacemit_pmic_irq_valid_mask(irqchip, i); + err = spacemit_pmic_update_bits(pmic, + irqchip->mask_base + i * irqchip->reg_stride, + valid_mask, + irqchip->mask_unmask_non_inverted ? 0 : valid_mask); + + if (err) + { + LOG_E("Mask IRQs failed error = %s", rt_strerror(err)); + rt_pic_cancel_irq(&irqchip->parent); + goto _fail; + } + + status = spacemit_pmic_read(pmic, + irqchip->status_base + i * irqchip->reg_stride); + + if ((rt_err_t)status < 0) + { + err = (rt_err_t)status; + LOG_E("Read IRQ status failed error = %s", rt_strerror(err)); + rt_pic_cancel_irq(&irqchip->parent); + goto _fail; + } + + if (irqchip->init_ack_masked && (status & valid_mask)) + { + err = spacemit_pmic_write(pmic, + irqchip->ack_base + i * irqchip->reg_stride, + status & valid_mask); + + if (err) + { + LOG_E("ACK masked IRQs failed error = %s", rt_strerror(err)); + rt_pic_cancel_irq(&irqchip->parent); + goto _fail; + } + } + } + + rt_pic_user_extends(&irqchip->parent); + + if ((err = rt_sem_init(&irqchip->irq_sem, "pmic-irq", 0, RT_IPC_FLAG_FIFO))) + { + rt_pic_cancel_irq(&irqchip->parent); + goto _fail; + } + + irqchip->irq_thread = rt_thread_create("spacemit-pmic", &spacemit_pmic_thread_isr, + irqchip, DM_THREAD_STACK_SIZE, RT_THREAD_PRIORITY_MAX / 2, 10); + + if (!irqchip->irq_thread) + { + rt_sem_detach(&irqchip->irq_sem); + rt_pic_cancel_irq(&irqchip->parent); + err = -RT_ENOMEM; + goto _fail; + } + + rt_thread_startup(irqchip->irq_thread); + + rt_hw_interrupt_install(pmic->irq, spacemit_pmic_isr, irqchip, "spacemit-pmic"); + rt_hw_interrupt_umask(pmic->irq); + } + + dev->user_data = pmic; + + if (mfd_data->shutdown.reg) + { + if (rt_dm_power_off_handler(dev, RT_DM_POWER_OFF_MODE_SHUTDOWN, + RT_DM_POWER_OFF_PRIO_PLATFORM, spacemit_pmic_shutdown)) + { + LOG_W("Add %s failed", "shutdown"); + } + } + + if (mfd_data->reboot.reg) + { + if (rt_dm_reboot_mode_register(dev, spacemit_pmic_reboot)) + { + LOG_W("Add %s failed", "reboot"); + } + } + + dev_np = dev->ofw_node; + pmic_ep = mfd_data->endpoint; + + for (int i = 0; i < mfd_data->endpoint_num; ++i, ++pmic_ep) + { + np = RT_NULL; + + if (!(np = rt_ofw_get_child_by_tag(dev_np, pmic_ep->ofw_name))) + { + if (pmic_ep->ofw_compatible) + { + np = rt_ofw_get_child_by_compatible(dev_np, pmic_ep->ofw_compatible); + } + + if (!np) + { + LOG_D("%s not found", pmic_ep->ofw_name); + + continue; + } + } + + if (!rt_ofw_node_is_available(np)) + { + continue; + } + + if (pmic_ep->irqs_nr) + { + if (!np && !(np = rt_ofw_append_child(dev_np, pmic_ep->ofw_name))) + { + continue; + } + + err = spacemit_pmic_ofw_bind_irq(mfd_data->irqchip, dev_np, np, pmic_ep); + + if (err == -RT_ENOMEM) + { + goto _out_put; + } + } + + err = create_spacemit_pmic_platform_device(platform_bus, pmic, pmic_ep->ofw_name, np); + + _out_put: + rt_ofw_node_put(np); + + if (err == -RT_ENOMEM) + { + LOG_E("No memory to create %s", pmic_ep->ofw_name); + break; + } + } + + return RT_EOK; + +_fail: + rt_mutex_delete(pmic->io_lock); + rt_free(pmic); + + return err; +} + +static const struct rt_ofw_node_id spacemit_pmic_i2c_ofw_ids[] = +{ + { .compatible = "spacemit,spm8821", .data = &spm8821_mfd_data }, + { .compatible = "spacemit,pm853", .data = &pm853_mfd_data }, + { .compatible = "spacemit,sy8810l", .data = &sy8810l_mfd_data }, + { /* sentinel */ }, +}; + +static struct rt_i2c_driver spacemit_pmic_i2c_driver = +{ + .ofw_ids = spacemit_pmic_i2c_ofw_ids, + + .probe = spacemit_pmic_i2c_probe, +}; + +static int spacemit_pmic_i2c_drv_register(void) +{ + rt_i2c_driver_register(&spacemit_pmic_i2c_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(spacemit_pmic_i2c_drv_register); diff --git a/bsp/spacemit/dm/nvmem/Kconfig b/bsp/spacemit/dm/nvmem/Kconfig new file mode 100644 index 000000000000..c8d868e37b1b --- /dev/null +++ b/bsp/spacemit/dm/nvmem/Kconfig @@ -0,0 +1,6 @@ +config RT_NVMEM_SPACEMIT_EFUSE + bool "Spacemit SoCs efuse support" + depends on RT_USING_NVMEM + depends on RT_USING_CLK + depends on RT_USING_RESET + default n diff --git a/bsp/spacemit/dm/nvmem/SConscript b/bsp/spacemit/dm/nvmem/SConscript new file mode 100644 index 000000000000..ca95989a8642 --- /dev/null +++ b/bsp/spacemit/dm/nvmem/SConscript @@ -0,0 +1,13 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_NVMEM_SPACEMIT_EFUSE']): + src += ['spacemit-efuse.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/nvmem/spacemit-efuse.c b/bsp/spacemit/dm/nvmem/spacemit-efuse.c new file mode 100644 index 000000000000..2a4d363d4e92 --- /dev/null +++ b/bsp/spacemit/dm/nvmem/spacemit-efuse.c @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include + +#define DBG_TAG "nvmem.spacemit" +#define DBG_LVL DBG_INFO +#include + +struct spacemit_efuse +{ + struct rt_nvmem_device parent; + + void *base; + struct rt_clk *clk; + struct rt_reset_control *rstc; + + rt_uint8_t *efuse_data; + rt_uint32_t size; +}; + +#define raw_to_spacemit_efuse(raw) rt_container_of(raw, struct spacemit_efuse, parent) + +static rt_err_t spacemit_k1_efuse_read(struct spacemit_efuse *efuse) +{ + rt_err_t err; + + if ((err = rt_clk_prepare_enable(efuse->clk))) + { + LOG_E("Failed to prepare/enable efuse clk"); + return err; + } + + if ((err = rt_reset_control_deassert(efuse->rstc))) + { + LOG_E("Failed to deassert efuse"); + rt_clk_disable_unprepare(efuse->clk); + return err; + } + + /* + * efuse data has been load into register by uboot already, + * just get efuse data from register + */ + for (int i = 0; i < efuse->size; i += 4) + { + *(rt_uint32_t *)(efuse->efuse_data + i) = *(rt_uint32_t *)(efuse->base + i); + } + + /* RESET_AES is shared with the crypto and RNG blocks. */ + rt_clk_disable_unprepare(efuse->clk); + + return err; +} + +static rt_ssize_t spacemit_efuse_read(struct rt_nvmem_device *ndev, int offset, + void *val, rt_size_t bytes) +{ + struct spacemit_efuse *efuse = raw_to_spacemit_efuse(ndev); + + rt_memcpy(val, &efuse->efuse_data[offset], bytes); + + return bytes; +} + +static rt_err_t spacemit_efuse_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + rt_uint64_t address, size; + struct spacemit_efuse *efuse; + struct rt_nvmem_device *nvmem; + struct rt_device *dev = &pdev->parent; + rt_err_t (*efuse_read)(struct spacemit_efuse *efuse); + + if (!(efuse_read = pdev->id->data)) + { + return -RT_EINVAL; + } + + if (!(efuse = rt_calloc(1, sizeof(*efuse)))) + { + return -RT_ENOMEM; + } + + if ((err = rt_dm_dev_get_address(dev, 0, &address, &size))) + { + goto _fail; + } + + efuse->base = rt_ioremap((void *)address, size); + if (!efuse->base) + { + err = -RT_EIO; + goto _fail; + } + + efuse->clk = rt_clk_get_by_index(dev, 0); + if (rt_is_err(efuse->clk)) + { + err = rt_ptr_err(efuse->clk); + goto _fail; + } + + efuse->rstc = rt_reset_control_get_by_index(dev, 0); + if (rt_is_err(efuse->rstc)) + { + err = rt_ptr_err(efuse->rstc); + goto _fail; + } + + efuse->size = rt_roundup(size, sizeof(rt_uint32_t)); + efuse->efuse_data = rt_calloc(1, efuse->size); + if (!efuse->efuse_data) + { + err = -RT_ENOMEM; + goto _fail; + } + + if ((err = efuse_read(efuse))) + { + goto _fail; + } + + nvmem = &efuse->parent; + nvmem->parent.ofw_node = dev->ofw_node; + nvmem->reg_read = spacemit_efuse_read, + nvmem->size = size; + nvmem->read_only = RT_TRUE; + nvmem->stride = 1; + nvmem->word_size = 1; + + if ((err = rt_nvmem_device_register(nvmem))) + { + goto _fail; + } + + return RT_EOK; + +_fail: + if (efuse->base) + { + rt_iounmap(efuse->base); + } + + if (!rt_is_err_or_null(efuse->clk)) + { + rt_clk_put(efuse->clk); + } + + if (!rt_is_err_or_null(efuse->rstc)) + { + rt_reset_control_put(efuse->rstc); + } + + if (efuse->efuse_data) + { + rt_free(efuse->efuse_data); + } + + rt_free(efuse); + + return err; +} + +static const struct rt_ofw_node_id spacemit_efuse_ofw_ids[] = +{ + { .compatible = "spacemit,k1-efuse", .data = &spacemit_k1_efuse_read }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_efuse_driver = +{ + .name = "nvmem-spacemit-efuse", + .ids = spacemit_efuse_ofw_ids, + + .probe = spacemit_efuse_probe, +}; + +RT_PLATFORM_DRIVER_EXPORT(spacemit_efuse_driver); diff --git a/bsp/spacemit/dm/pci/Kconfig b/bsp/spacemit/dm/pci/Kconfig new file mode 100644 index 000000000000..286a3e0edbe2 --- /dev/null +++ b/bsp/spacemit/dm/pci/Kconfig @@ -0,0 +1,10 @@ +config RT_PCI_DW_SPACEMIT_K1X + bool "Spacemit k1x DesignWare PCIe" + depends on RT_PCI_DW + depends on RT_USING_PIN + depends on RT_USING_PINCTRL + depends on RT_USING_RESET + depends on RT_USING_REGULATOR + select RT_PCI_DW_HOST + select RT_PCI_DW_EP + default n diff --git a/bsp/spacemit/dm/pci/SConscript b/bsp/spacemit/dm/pci/SConscript new file mode 100644 index 000000000000..5c28842a96b4 --- /dev/null +++ b/bsp/spacemit/dm/pci/SConscript @@ -0,0 +1,15 @@ +from building import * + +group = [] + +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include', cwd + '/../../../../components/drivers/pci', cwd + '/../../../../components/drivers/pci/host/dw'] + +src = [] + +if GetDepend(['RT_PCI_DW_SPACEMIT_K1X']): + src += ['pcie-k1x.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/pci/pcie-k1x.c b/bsp/spacemit/dm/pci/pcie-k1x.c new file mode 100644 index 000000000000..bf3e399441c5 --- /dev/null +++ b/bsp/spacemit/dm/pci/pcie-k1x.c @@ -0,0 +1,1366 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#define DBG_TAG "pci.dw.k1x" +#define DBG_LVL DBG_INFO +#include + +#include "pcie-dw.h" + +#define PCIE_VENDORID_MASK 0xffff +#define PCIE_DEVICEID_SHIFT 16 +#define K1X_PCIE_VENDOR_ID 0x201f +#define k1X_PCIE_DEVICE_ID 0x0001 + +/* PCIe controller wrapper k1x configuration registers */ + +#define K1X_PHY_AHB_IRQ_EN 0x0000 +#define IRQ_EN RT_BIT(0) +#define PME_TURN_OFF RT_BIT(5) + +#define K1X_PHY_AHB_IRQSTATUS_INTX 0x0008 +#define INTA RT_BIT(6) +#define INTB RT_BIT(7) +#define INTC RT_BIT(8) +#define INTD RT_BIT(9) +#define LEG_EP_INTERRUPTS (INTA | INTB | INTC | INTD) +#define INTX_MASK RT_GENMASK(9, 6) +#define INTX_SHIFT 6 + +#define K1X_PHY_AHB_IRQENABLE_SET_INTX 0x000c + +#define K1X_PHY_AHB_IRQSTATUS_MSI 0x0010 +#define MSI RT_BIT(11) +#define PCIE_REMOTE_INTERRUPT RT_BIT(31) +/* DMA write channel 0~7 irq*/ +#define EDMA_INT0 RT_BIT(0) +#define EDMA_INT1 RT_BIT(1) +#define EDMA_INT2 RT_BIT(2) +#define EDMA_INT3 RT_BIT(3) +#define EDMA_INT4 RT_BIT(4) +#define EDMA_INT5 RT_BIT(5) +#define EDMA_INT6 RT_BIT(6) +#define EDMA_INT7 RT_BIT(7) +/* DMA read channel 0~7 irq*/ +#define EDMA_INT8 RT_BIT(8) +#define EDMA_INT9 RT_BIT(9) +#define EDMA_INT10 RT_BIT(10) +#define EDMA_INT11 RT_BIT(11) +#define EDMA_INT12 RT_BIT(12) +#define EDMA_INT13 RT_BIT(13) +#define EDMA_INT14 RT_BIT(14) +#define EDMA_INT15 RT_BIT(15) +#define DMA_READ_INT RT_GENMASK(11, 8) + +#define K1X_PHY_AHB_IRQENABLE_SET_MSI 0x0014 + +#define PCIECTRL_K1X_CONF_DEVICE_CMD 0x0000 +#define LTSSM_EN RT_BIT(6) +/* Perst input value in ep mode */ +#define PCIE_PERST_IN RT_BIT(7) +#define PCIE_AUX_PWR_DET RT_BIT(9) +/* Perst GPIO en in RC mode 1: perst# low, 0: perst# high */ +#define PCIE_RC_PERST RT_BIT(12) +/* Wake# GPIO in EP mode 1: Wake# low, 0: Wake# high */ +#define PCIE_EP_WAKE RT_BIT(13) +#define APP_HOLD_PHY_RST RT_BIT(30) +/* BIT31 0: EP, 1: RC*/ +#define DEVICE_TYPE_RC RT_BIT(31) + +#define PCIE_CTRL_LOGIC 0x0004 +#define PCIE_IGNORE_PERSTN RT_BIT(2) + +#define K1X_PHY_AHB_LINK_STS 0x0004 +#define SMLH_LINK_UP RT_BIT(1) +#define RDLH_LINK_UP RT_BIT(12) +#define PCIE_CLIENT_DEBUG_LTSSM_MASK RT_GENMASK(11, 6) +#define PCIE_CLIENT_DEBUG_LTSSM_L1 (RT_BIT(10) | RT_BIT(8)) +#define PCIE_CLIENT_DEBUG_LTSSM_L2 (RT_BIT(10) | RT_BIT(8) | RT_BIT(6)) + +#define ADDR_INTR_STATUS1 0x0018 +#define ADDR_INTR_ENABLE1 0x001c +#define MSI_INT RT_BIT(0) +#define MSIX_INT RT_GENMASK(8, 1) + +#define ADDR_MSI_RECV_CTRL 0x0080 +#define MSI_MON_EN RT_BIT(0) +#define MSIX_MON_EN RT_GENMASK(8, 1) +#define MSIX_AFIFO_FULL RT_BIT(30) +#define MSIX_AFIFO_EMPTY RT_BIT(29) +#define ADDR_MSI_RECV_ADDR0 0x0084 +#define ADDR_MSIX_MON_MASK 0x0088 +#define ADDR_MSIX_MON_BASE0 0x008c + +#define ADDR_MON_FIFO_DATA0 0x00b0 +#define ADDR_MON_FIFO_DATA1 0x00b4 +#define FIFO_EMPTY 0xffffffff +#define FIFO_LEN 32 +#define INT_VEC_MASK RT_GENMASK(7, 0) + +#define EXP_CAP_ID_OFFSET 0x70 + +#define PCIECTRL_K1X_CONF_INTX_ASSERT 0x0124 +#define PCIECTRL_K1X_CONF_INTX_DEASSERT 0x0128 + +/*RC write config 0xD28 offset register which equal with ELBI offset 0x028 addr*/ +#define PCIE_ELBI_EP_DMA_IRQ_STATUS 0x028 +#define PC_TO_EP_INT 0x3fffffff + +#define PCIE_ELBI_EP_DMA_IRQ_MASK 0x02c +#define PC_TO_EP_INT_MASK 0x3fffffff + +#define PCIE_ELBI_EP_MSI_REASON 0x018 + +#define PCIE_LINK_IS_L2(x) (((x) & PCIE_CLIENT_DEBUG_LTSSM_MASK) == PCIE_CLIENT_DEBUG_LTSSM_L2) + +struct k1x_pcie_soc_data +{ + enum dw_pcie_device_mode mode; +}; + +struct k1x_pcie +{ + struct dw_pcie pci; + + int irq; + void *base; + void *elbi_base; + void *dma_base; + void *phy_ahb; + void *phy_addr; + void *conf0_addr; + void *phy0_addr; + + enum dw_pcie_device_mode mode; + + struct rt_clk *clk_master; + struct rt_reset_control *rstc; + + rt_base_t pwr_on_pin; + rt_uint8_t pwr_on_active_val; + + rt_uint32_t pcie_rcal; + rt_uint32_t port_id; + rt_uint32_t num_lanes; + rt_uint32_t link_gen; + + fdt32_t msi_phandle_cell; + + void *msix_data; + rt_ubase_t msix_data_phy; + + struct rt_ofw_node *pic_np; + struct rt_pic pic; +}; + +#define to_k1x_pcie(dw_pcie) rt_container_of(dw_pcie, struct k1x_pcie, pci) + +static rt_bool_t porta_init_done = RT_FALSE; + +rt_inline rt_uint32_t k1x_pcie_readl_dma(struct k1x_pcie *k1x, int offset) +{ + return HWREG32(k1x->dma_base + offset); +} + +rt_inline void k1x_pcie_writel_dma(struct k1x_pcie *k1x, int offset, rt_uint32_t val) +{ + HWREG32(k1x->dma_base + offset) = val; +} + +rt_inline rt_uint32_t k1x_pcie_readw_dma(struct k1x_pcie *k1x, int offset) +{ + return (rt_uint32_t)HWREG16(k1x->dma_base + offset); +} + +rt_inline void k1x_pcie_writew_dma(struct k1x_pcie *k1x, int offset, rt_uint32_t val) +{ + HWREG16(k1x->dma_base + offset) = (rt_uint16_t)val; +} + +rt_inline rt_uint32_t k1x_pcie_readl(struct k1x_pcie *k1x, int offset) +{ + return HWREG32(k1x->base + offset); +} + +rt_inline void k1x_pcie_writel(struct k1x_pcie *k1x, int offset, rt_uint32_t val) +{ + HWREG32(k1x->base + offset) = val; +} + +rt_inline rt_uint32_t k1x_pcie_readl_elbi(struct k1x_pcie *k1x, int offset) +{ + return HWREG32(k1x->elbi_base + offset); +} + +rt_inline void k1x_pcie_writel_elbi(struct k1x_pcie *k1x, int offset, rt_uint32_t val) +{ + HWREG32(k1x->elbi_base + offset) = val; +} + +rt_inline rt_uint32_t k1x_pcie_phy_ahb_readl(struct k1x_pcie *k1x, int offset) +{ + return HWREG32(k1x->phy_ahb + offset); +} + +rt_inline void k1x_pcie_phy_ahb_writel(struct k1x_pcie *k1x, int offset, rt_uint32_t val) +{ + HWREG32(k1x->phy_ahb + offset) = val; +} + +rt_inline rt_uint32_t k1x_pcie_phy_reg_readl(struct k1x_pcie *k1x, int offset) +{ + return HWREG32(k1x->phy_addr + offset); +} + +rt_inline void k1x_pcie_phy_reg_writel(struct k1x_pcie *k1x, int offset, rt_uint32_t val) +{ + HWREG32(k1x->phy_addr + offset) = val; +} + +rt_inline rt_uint32_t k1x_pcie_conf0_reg_readl(struct k1x_pcie *k1x, int offset) +{ + return HWREG32(k1x->conf0_addr + offset); +} + +rt_inline void k1x_pcie_conf0_reg_writel(struct k1x_pcie *k1x, int offset, rt_uint32_t val) +{ + HWREG32(k1x->conf0_addr + offset) = val; +} + +rt_inline rt_uint32_t k1x_pcie_phy0_reg_readl(struct k1x_pcie *k1x, int offset) +{ + return HWREG32(k1x->phy0_addr + offset); +} + +rt_inline void k1x_pcie_phy0_reg_writel(struct k1x_pcie *k1x, int offset, rt_uint32_t val) +{ + HWREG32(k1x->phy0_addr + offset) = val; +} + +static rt_err_t k1x_pcie_ep_init(struct dw_pcie_ep *ep) +{ + rt_uint32_t reg; + struct dw_pcie *pci = to_dw_pcie_from_endpoint(ep); + struct k1x_pcie *k1x = to_k1x_pcie(pci); + + /* Enable wrapper interrupts */ + reg = k1x_pcie_phy_ahb_readl(k1x, K1X_PHY_AHB_IRQENABLE_SET_MSI); + reg |= PCIE_REMOTE_INTERRUPT | DMA_READ_INT; + k1x_pcie_phy_ahb_writel(k1x, K1X_PHY_AHB_IRQENABLE_SET_MSI, reg); + + reg = k1x_pcie_phy_ahb_readl(k1x, K1X_PHY_AHB_IRQ_EN); + reg |= IRQ_EN; + k1x_pcie_phy_ahb_writel(k1x, K1X_PHY_AHB_IRQ_EN, reg); + + reg = k1x_pcie_readl_elbi(k1x, PCIE_ELBI_EP_DMA_IRQ_MASK); + reg |= PC_TO_EP_INT_MASK; + k1x_pcie_writel_elbi(k1x, PCIE_ELBI_EP_DMA_IRQ_MASK, reg); + + return RT_EOK; +} + +static rt_err_t k1x_pcie_raise_irq(struct dw_pcie_ep *ep, rt_uint8_t func_no, + enum rt_pci_ep_irq type, unsigned irq) +{ + switch (type) + { + case RT_PCI_EP_IRQ_LEGACY: + LOG_E("Unsupported INTx"); + return -RT_EINVAL; + + case RT_PCI_EP_IRQ_MSI: + dw_pcie_ep_raise_msi_irq(ep, func_no, irq); + break; + + case RT_PCI_EP_IRQ_MSIX: + dw_pcie_ep_raise_msix_irq(ep, func_no, irq); + break; + + default: + LOG_E("Unknown IRQ type = %d", type); + } + + return RT_EOK; +} + +static struct dw_pcie_ep_ops pcie_ep_ops = +{ + .ep_init = k1x_pcie_ep_init, + .raise_irq = k1x_pcie_raise_irq, +}; + +static rt_err_t k1x_add_pcie_ep(struct k1x_pcie *k1x, struct rt_device *dev) +{ + rt_err_t err; + struct dw_pcie *pci = &k1x->pci; + struct dw_pcie_ep *ep = &pci->endpoint; + + ep->ops = &pcie_ep_ops; + + if (!(k1x->elbi_base = rt_dm_dev_iomap_by_name(dev, "elbi"))) + { + return -RT_EIO; + } + + if (!(k1x->dma_base = rt_dm_dev_iomap_by_name(dev, "dma"))) + { + return -RT_EIO; + } + + if ((err = dw_pcie_ep_init(ep))) + { + LOG_E("Failed to initialize endpoint"); + return err; + } + + return RT_EOK; +} + +static rt_err_t k1x_pcie_host_init(struct dw_pcie_port *port) +{ + rt_err_t err; + rt_uint32_t reg; + struct dw_pcie *pci = to_dw_pcie_from_port(port); + struct k1x_pcie *k1x = to_k1x_pcie(pci); + + rt_thread_mdelay(100); + + /* Set Perst# gpio high state */ + reg = k1x_pcie_readl(k1x, PCIECTRL_K1X_CONF_DEVICE_CMD); + reg &= ~PCIE_RC_PERST; + k1x_pcie_writel(k1x, PCIECTRL_K1X_CONF_DEVICE_CMD, reg); + + /* Enable MSI interrupts */ + reg = k1x_pcie_phy_ahb_readl(k1x, K1X_PHY_AHB_IRQENABLE_SET_MSI); + reg |= MSI; + k1x_pcie_phy_ahb_writel(k1x, K1X_PHY_AHB_IRQENABLE_SET_MSI, reg); + + reg = k1x_pcie_phy_ahb_readl(k1x, K1X_PHY_AHB_IRQENABLE_SET_INTX); + reg |= LEG_EP_INTERRUPTS; + k1x_pcie_phy_ahb_writel(k1x, K1X_PHY_AHB_IRQENABLE_SET_INTX, reg); + + reg = k1x_pcie_phy_ahb_readl(k1x, K1X_PHY_AHB_IRQ_EN); + reg |= IRQ_EN; + k1x_pcie_phy_ahb_writel(k1x, K1X_PHY_AHB_IRQ_EN, reg); + + reg = k1x_pcie_phy_ahb_readl(k1x, ADDR_INTR_ENABLE1); + reg |= (MSI_INT | MSIX_INT); + k1x_pcie_phy_ahb_writel(k1x, ADDR_INTR_ENABLE1, reg); + + /* Configure the root complex before starting link training. */ + dw_pcie_setup_rc(port); + + if (!dw_pcie_link_up(pci) && pci->ops->start_link) + { + if ((err = pci->ops->start_link(pci))) + { + LOG_E("Failed to start PCIe%d link: %s", k1x->port_id, + rt_strerror(err)); + return err; + } + } + + /* Keep the host registered even when an endpoint trains later. */ + if ((err = dw_pcie_wait_for_link(pci))) + { + reg = k1x_pcie_phy_ahb_readl(k1x, K1X_PHY_AHB_LINK_STS); + LOG_W("PCIe%d link down, status=0x%08x", k1x->port_id, reg); + } + else + { + reg = dw_pcie_readw_dbi(pci, EXP_CAP_ID_OFFSET + PCIER_LINK_STA); + LOG_I("PCIe%d Link up, Gen%i", k1x->port_id, + reg & PCIEM_LINK_STA_SPEED); + } + + return RT_EOK; +} + +static rt_err_t k1x_pcie_msi_host_init(struct dw_pcie_port *port) +{ + rt_uint32_t reg; + rt_uint64_t msi_target; + struct dw_pcie *pci = to_dw_pcie_from_port(port); + struct k1x_pcie *k1x = to_k1x_pcie(pci); + + /* MSI Start */ + port->msi_data = rt_dma_alloc_coherent(pci->dev, sizeof(rt_uint64_t), + &port->msi_data_phy); + if (!port->msi_data) + { + goto _msix_init; + } + msi_target = (rt_uint64_t)port->msi_data_phy; + + /* Program the msi_data */ + dw_pcie_writel_dbi(pci, PCIE_MSI_ADDR_LO, rt_lower_32_bits(msi_target)); + dw_pcie_writel_dbi(pci, PCIE_MSI_ADDR_HI, rt_upper_32_bits(msi_target)); + + reg = k1x_pcie_phy_ahb_readl(k1x, ADDR_MSI_RECV_CTRL); + reg |= MSI_MON_EN; + k1x_pcie_phy_ahb_writel(k1x, ADDR_MSI_RECV_CTRL, reg); + k1x_pcie_phy_ahb_writel(k1x, ADDR_MSI_RECV_ADDR0, (rt_lower_32_bits(msi_target) >> 2)); + /* MSI End */ + +_msix_init: + /* MSI-X Start */ + k1x->msix_data = rt_dma_alloc_coherent(pci->dev, sizeof(rt_uint64_t), + &k1x->msix_data_phy); + if (!k1x->msix_data) + { + goto _end; + } + msi_target = (rt_uint64_t)k1x->msix_data_phy; + + reg = k1x_pcie_phy_ahb_readl(k1x, ADDR_MSI_RECV_CTRL); + reg |= MSIX_MON_EN; + k1x_pcie_phy_ahb_writel(k1x, ADDR_MSI_RECV_CTRL, reg); + k1x_pcie_phy_ahb_writel(k1x, ADDR_MSIX_MON_BASE0, (rt_lower_32_bits(msi_target) >> 2)); + /* MSI-X End */ + +_end: + return RT_EOK; +} + +static const struct dw_pcie_host_ops k1x_pcie_host_ops = +{ + .host_init = k1x_pcie_host_init, + .msi_host_init = k1x_pcie_msi_host_init, +}; + +static rt_bool_t k1x_pcie_link_up(struct dw_pcie *pci) +{ + struct k1x_pcie *k1x = to_k1x_pcie(pci); + rt_uint32_t reg = k1x_pcie_phy_ahb_readl(k1x, K1X_PHY_AHB_LINK_STS); + + return (reg & RDLH_LINK_UP) && (reg & SMLH_LINK_UP); +} + +static rt_err_t k1x_pcie_establish_link(struct dw_pcie *pci) +{ + rt_uint32_t reg; + struct k1x_pcie *k1x = to_k1x_pcie(pci); + + if (k1x->mode == DW_PCIE_EP_TYPE) + { + rt_uint32_t cnt = 0; + do { + reg = k1x_pcie_readl(k1x, PCIECTRL_K1X_CONF_DEVICE_CMD); + + if ((reg & RT_BIT(7)) == RT_BIT(7)) + { + break; + } + + rt_hw_us_delay(10); + cnt += 1; + } while (cnt < 300000); + } + + if (dw_pcie_link_up(pci)) + { + LOG_E("Link is already up"); + return RT_EOK; + } + + reg = k1x_pcie_readl(k1x, PCIECTRL_K1X_CONF_DEVICE_CMD); + reg |= LTSSM_EN; + reg &= ~APP_HOLD_PHY_RST; + k1x_pcie_writel(k1x, PCIECTRL_K1X_CONF_DEVICE_CMD, reg); + + LOG_D("LTSSM Enable"); + + return RT_EOK; +} + +static void k1x_pcie_stop_link(struct dw_pcie *pci) +{ + rt_uint32_t reg; + struct k1x_pcie *k1x = to_k1x_pcie(pci); + + reg = k1x_pcie_readl(k1x, PCIECTRL_K1X_CONF_DEVICE_CMD); + reg &= ~LTSSM_EN; + k1x_pcie_writel(k1x, PCIECTRL_K1X_CONF_DEVICE_CMD, reg); +} + +static const struct dw_pcie_ops dw_pcie_ops = +{ + .link_up = k1x_pcie_link_up, + .start_link = k1x_pcie_establish_link, + .stop_link = k1x_pcie_stop_link, +}; + +static void k1x_pci_irq_mask(struct rt_pic_irq *pirq) +{ + if (pirq->msi_desc) + { + rt_pci_msi_mask_irq(pirq); + } +} + +static void k1x_pci_irq_unmask(struct rt_pic_irq *pirq) +{ + if (pirq->msi_desc) + { + rt_pci_msi_unmask_irq(pirq); + } +} + +static void k1x_pcie_irq_compose_msi_msg(struct rt_pic_irq *pirq, struct rt_pci_msi_msg *msg) +{ + rt_uint64_t msi_target; + struct k1x_pcie *k1x = pirq->pic->priv_data; + struct dw_pcie_port *port = &k1x->pci.port; + + msi_target = (rt_uint64_t)port->msi_data_phy; + + msg->address_lo = rt_lower_32_bits(msi_target); + msg->address_hi = rt_upper_32_bits(msi_target); + msg->data = pirq->hwirq; +} + +static int k1x_pcie_irq_alloc_msi(struct rt_pic *pic, struct rt_pci_msi_desc *msi_desc) +{ + rt_ubase_t level; + int irq, virq, hwirq; + struct rt_pic_irq *pirq; + struct k1x_pcie *k1x = pic->priv_data; + struct dw_pcie_port *port = &k1x->pci.port; + + level = rt_spin_lock_irqsave(&port->lock); + hwirq = rt_bitmap_next_clear_bit(port->msi_map, 0, MAX_MSI_IRQS); + virq = hwirq + RT_PCI_INTX_PIN_MAX; + + if (hwirq >= MAX_MSI_IRQS || virq >= pic->irq_nr) + { + irq = -RT_EEMPTY; + goto _out_lock; + } + + pirq = rt_pic_find_irq(pic, virq); + + irq = rt_pic_config_irq(pic, virq, hwirq); + pirq->mode = RT_IRQ_MODE_EDGE_RISING; + + rt_bitmap_set_bit(port->msi_map, hwirq); + +_out_lock: + rt_spin_unlock_irqrestore(&port->lock, level); + + return irq; +} + +static void k1x_pcie_irq_free_msi(struct rt_pic *pic, int irq) +{ + rt_ubase_t level; + struct rt_pic_irq *pirq; + struct k1x_pcie *k1x = pic->priv_data; + struct dw_pcie_port *port = &k1x->pci.port; + + pirq = rt_pic_find_pirq(pic, irq); + + if (!pirq) + { + return; + } + + level = rt_spin_lock_irqsave(&port->lock); + rt_bitmap_clear_bit(port->msi_map, pirq->hwirq); + rt_spin_unlock_irqrestore(&port->lock, level); +} + +static int k1x_pcie_irq_map(struct rt_pic *pic, int hwirq, rt_uint32_t mode) +{ + int irq; + struct rt_pic_irq *pirq = rt_pic_find_irq(pic, hwirq); + + if (pirq) + { + if (pirq->irq >= 0) + { + irq = pirq->irq; + } + else + { + irq = rt_pic_config_irq(pic, hwirq, hwirq); + rt_pic_irq_set_triger_mode(irq, RT_IRQ_MODE_LEVEL_HIGH); + } + } + else + { + irq = -1; + } + + return irq; +} + +static rt_err_t k1x_pcie_irq_parse(struct rt_pic *pic, + struct rt_ofw_cell_args *args, struct rt_pic_irq *out_pirq) +{ + rt_err_t err = RT_EOK; + + if (args->args_count == 1) + { + out_pirq->hwirq = args->args[0]; + out_pirq->mode = RT_IRQ_MODE_LEVEL_HIGH; + } + else + { + err = -RT_EINVAL; + } + + return err; +} + +const static struct rt_pic_ops k1x_pcie_pic_ops = +{ + .name = "K1X-PCIe", + .irq_mask = k1x_pci_irq_mask, + .irq_unmask = k1x_pci_irq_unmask, + .irq_compose_msi_msg = k1x_pcie_irq_compose_msi_msg, + .irq_alloc_msi = k1x_pcie_irq_alloc_msi, + .irq_free_msi = k1x_pcie_irq_free_msi, + .irq_map = k1x_pcie_irq_map, + .irq_parse = k1x_pcie_irq_parse, +}; + +static void k1x_pcie_pic_isr(int irqno, void *param) +{ + rt_uint32_t reg, hwirq; + struct rt_pic_irq *pirq; + struct k1x_pcie *k1x = param; + + reg = k1x_pcie_phy_ahb_readl(k1x, ADDR_INTR_STATUS1); + k1x_pcie_phy_ahb_writel(k1x, ADDR_INTR_STATUS1, reg); + + /* MSI int handler */ + if ((reg & MSI_INT) | (reg & MSIX_INT)) + { + rt_uint32_t val; + + if (k1x_pcie_phy_ahb_readl(k1x, ADDR_MSI_RECV_CTRL) & MSIX_AFIFO_FULL) + { + LOG_W("AXI monitor FIFO FULL"); + } + + for (int i = 0; i < FIFO_LEN; ++i) + { + if (k1x_pcie_phy_ahb_readl(k1x, ADDR_MON_FIFO_DATA0) == FIFO_EMPTY) + { + break; + } + val = k1x_pcie_phy_ahb_readl(k1x, ADDR_MON_FIFO_DATA1); + /* In fact, val is the hwirq which equals with msi_data + msi vector */ + val &= INT_VEC_MASK; + + if ((pirq = rt_pic_find_irq(&k1x->pic, val + RT_PCI_INTX_PIN_MAX))) + { + rt_pic_handle_isr(pirq); + } + } + } + + /* Legacy INTx */ + reg = k1x_pcie_phy_ahb_readl(k1x, K1X_PHY_AHB_IRQSTATUS_INTX); + k1x_pcie_phy_ahb_writel(k1x, K1X_PHY_AHB_IRQSTATUS_INTX, reg); + reg = (reg & INTX_MASK) >> INTX_SHIFT; + + if (reg) + { + LOG_D("Legacy INTx interrupt received"); + } + + while (reg) + { + hwirq = __rt_ffs(reg) - 1; + reg &= ~RT_BIT(hwirq); + + pirq = rt_pic_find_irq(&k1x->pic, hwirq); + + if (pirq) + { + rt_pic_handle_isr(pirq); + } + else + { + LOG_E("Unexpected IRQ INTx #%c", 'A' + hwirq); + } + } +} + +static rt_err_t k1x_add_pcie_port(struct k1x_pcie *k1x, struct rt_device *dev) +{ + rt_err_t err; + rt_uint32_t reg; + struct dw_pcie *pci = &k1x->pci; + struct dw_pcie_port *port = &pci->port; + struct rt_ofw_node *np = dev->ofw_node, *msi_np; + + /* Set Perst# (fundamental rstc) gpio low state */ + reg = k1x_pcie_readl(k1x, PCIECTRL_K1X_CONF_DEVICE_CMD); + reg |= PCIE_RC_PERST; + k1x_pcie_writel(k1x, PCIECTRL_K1X_CONF_DEVICE_CMD, reg); + + port->sys_irq = rt_dm_dev_get_irq(dev, 0); + if (port->sys_irq < 0) + { + LOG_E("Missing IRQ resource"); + return port->sys_irq; + } + + if (!(pci->dbi_base = rt_dm_dev_iomap_by_name(dev, "dbi"))) + { + return -RT_EIO; + } + + if (!(pci->atu_base = rt_dm_dev_iomap_by_name(dev, "atu"))) + { + return -RT_EIO; + } + + if (!(msi_np = rt_ofw_append_child(np, "msi-controller"))) + { + return -RT_ENOMEM; + } + + k1x->msi_phandle_cell = cpu_to_fdt32(msi_np->phandle); + + if ((err = rt_ofw_append_prop(np, "msi-parent", sizeof(fdt32_t), &k1x->msi_phandle_cell))) + { + return err; + } + + if (!(k1x->pic_np = rt_ofw_get_child_by_tag(np, "interrupt-controller"))) + { + LOG_E("INTx ofw node not found"); + return -RT_EIO; + } + + port->ops = &k1x_pcie_host_ops; + port->irq_count = RT_PCI_INTX_PIN_MAX + MAX_MSI_IRQS; + + k1x->pic.priv_data = k1x; + k1x->pic.ops = &k1x_pcie_pic_ops; + rt_pic_linear_irq(&k1x->pic, port->irq_count); + rt_pic_user_extends(&k1x->pic); + rt_ofw_data(k1x->pic_np) = &k1x->pic; + rt_ofw_node_put(k1x->pic_np); + + /* For MSI */ + rt_ofw_data(msi_np) = &k1x->pic; + + rt_hw_interrupt_install(port->sys_irq, k1x_pcie_pic_isr, k1x, "k1x-pcie"); + rt_hw_interrupt_umask(port->sys_irq); + + /* Init ID */ + dw_pcie_dbi_ro_writable_enable(pci, RT_TRUE); + dw_pcie_writew_dbi(pci, PCIR_VENDOR, K1X_PCIE_VENDOR_ID); + dw_pcie_writew_dbi(pci, PCIR_DEVICE, k1X_PCIE_DEVICE_ID); + dw_pcie_dbi_ro_writable_enable(pci, RT_FALSE); + + if ((err = dw_pcie_host_init(port))) + { + LOG_E("Failed to initialize host"); + return err; + } + + return RT_EOK; +} + +/* Local cpu interrupt, vendor specific */ +static void k1x_pcie_isr(int irqno, void *param) +{ + rt_uint32_t reg, reg_ahb; + struct k1x_pcie *k1x = param; + + reg = k1x_pcie_readl_elbi(k1x, PCIE_ELBI_EP_DMA_IRQ_STATUS); + /* Write 0 to clear the irq*/ + k1x_pcie_writel_elbi(k1x, PCIE_ELBI_EP_DMA_IRQ_STATUS, 0); + reg_ahb = k1x_pcie_phy_ahb_readl(k1x, K1X_PHY_AHB_IRQSTATUS_MSI); + +_repeat: + if (reg & PC_TO_EP_INT) + { + LOG_I("EP ISR"); + } + if (reg_ahb & DMA_READ_INT) + { + LOG_I("DMA ISR"); + } + + reg = k1x_pcie_readl_elbi(k1x, PCIE_ELBI_EP_DMA_IRQ_STATUS); + if (reg & PC_TO_EP_INT) + { + k1x_pcie_writel_elbi(k1x, PCIE_ELBI_EP_DMA_IRQ_STATUS, 0); + goto _repeat; + } +} + +/* Wait porta rterm done */ +static void porta_rterm(struct k1x_pcie *k1x) +{ + rt_uint32_t val; + int rd_data, count = 0; + + k1x_pcie_conf0_reg_writel(k1x, 0, 0x4000003f); + + val = k1x_pcie_conf0_reg_readl(k1x, 0); + val &= 0xbfffffff; + k1x_pcie_conf0_reg_writel(k1x, 0, val); + + /* Set refclk model */ + val = k1x_pcie_phy0_reg_readl(k1x, 0x17 << 2); + val |= 0x1 << 10; + k1x_pcie_phy0_reg_writel(k1x, 0x17 << 2, val); + + val = k1x_pcie_phy0_reg_readl(k1x, 0x17 << 2); + val &= ~(0x3 << 8); + k1x_pcie_phy0_reg_writel(k1x, 0x17 << 2, val); + + /* Driver mode */ + val = k1x_pcie_phy0_reg_readl(k1x, 0x17 << 2); + val |= 0x1 << 8; + k1x_pcie_phy0_reg_writel(k1x, 0x17 << 2, val); + + val = k1x_pcie_phy0_reg_readl(k1x, 0x12 << 2); + val &= 0xffff0fff; + k1x_pcie_phy0_reg_writel(k1x, 0x12 << 2, val); + + val = k1x_pcie_phy0_reg_readl(k1x, 0x12 << 2); + val |= 0x00002000; + k1x_pcie_phy0_reg_writel(k1x, 0x12 << 2, val); + + val = k1x_pcie_phy0_reg_readl(k1x, 0x13 << 2); + val |= 0x1 << 4; + k1x_pcie_phy0_reg_writel(k1x, 0x13 << 2, val); + + val = k1x_pcie_phy0_reg_readl(k1x, 0x12 << 2); + val &= 0xfff0ffff; + k1x_pcie_phy0_reg_writel(k1x, 0x12 << 2, val); + + k1x_pcie_phy0_reg_writel(k1x, 0x02 << 2, 0x00000b78); + + k1x_pcie_phy0_reg_writel(k1x, 0x06 << 2, 0x00000400); + + /* Wait pm0 rterm done */ + do { + rd_data = k1x_pcie_phy0_reg_readl(k1x, 0x21 * 4); + + if (count++ > 5000) + { + LOG_E("Read PCIe%d phy rd_data time out", 0); + break; + } + } while (((rd_data >> 10) & 0x1) == 0); /* Waiting PCIe portA readonly_reg2[2] r_tune_done==1 */ +} + +/* Force rterm value to porta/b/c */ +static void rterm_force(struct k1x_pcie *k1x, rt_uint32_t pcie_rcal) +{ + rt_uint32_t val = 0; + int lane = k1x->num_lanes; + + /* 2. Write pma0 rterm value LSB[3:0](read0nly1[3:0]) to lane0/1 rx_reg1 */ + for (int i = 0; i < lane; ++i) + { + val = k1x_pcie_phy_reg_readl(k1x, ((0x14 << 2) + 0x400 * i)); + val &= ~(0xf << 8); + val |= (pcie_rcal & 0xf) << 8; + k1x_pcie_phy_reg_writel(k1x, ((0x14 << 2) + 0x400 * i), val); + } + /* 3. Set lane0/1 rx_reg4 bit5=0 */ + for (int i = 0; i < lane; ++i) + { + val = k1x_pcie_phy_reg_readl(k1x, ((0x15 << 2) + 0x400 * i)); + val &= ~(1 << 5); + k1x_pcie_phy_reg_writel(k1x, ((0x15 << 2) + 0x400 * i), val); + } + + /* 4. Write pma0 rterm value MSB[7:4](readonly1[7:4]) to lane0/1 tx_reg1[7:4] */ + for (int i = 0; i < lane; ++i) + { + val = k1x_pcie_phy_reg_readl(k1x, ((0x19 << 2) + 0x400 * i)); + val &= ~(0xf << 12); + val |= ((pcie_rcal >> 4) & 0xf) << 12; + k1x_pcie_phy_reg_writel(k1x, ((0x19 << 2) + 0x400 * i), val); + } + + /* 5. Set lane0/1 tx_reg3 bit1=1 */ + for (int i = 0; i < lane; ++i) + { + val = k1x_pcie_phy_reg_readl(k1x, ((0x19 << 2) + 0x400 * i)); + val |= 1 << 25; + k1x_pcie_phy_reg_writel(k1x, ((0x19 << 2) + 0x400 * i), val); + } + + /* 6. Adjust rc calrefclk freq */ + val = k1x_pcie_phy_reg_readl(k1x, 0x8 << 2); + val &= ~(0x7 << 29); + val |= 0x3 << 29; + k1x_pcie_phy_reg_writel(k1x, 0x8 << 2, val); + + /* 7. Set lane0/1 rc_cal_reg1[6]=1 */ + for (int i = 0; i < lane; ++i) + { + val = k1x_pcie_phy_reg_readl(k1x, ((0x8 << 2) + 0x400 * i)); + val &= ~(1 << 22); + k1x_pcie_phy_reg_writel(k1x, ((0x8 << 2) + 0x400 * i), val); + } + for (int i = 0; i < lane; ++i) + { + val = k1x_pcie_phy_reg_readl(k1x, ((0x8 << 2) + 0x400 * i)); + val |= 1 << 22; + k1x_pcie_phy_reg_writel(k1x, ((0x8 << 2) + 0x400 * i), val); + } +} + +static rt_err_t init_phy(struct k1x_pcie *k1x) +{ + int count = 0; + rt_uint32_t reg, rd_data, pcie_rcal, val = 0; + + if (k1x->port_id != 0) + { + if (!porta_init_done) + { + porta_rterm(k1x); + pcie_rcal = k1x_pcie_phy0_reg_readl(k1x, 0x21 << 2); + + val = k1x_pcie_conf0_reg_readl(k1x, 0); + val &= ~0x4000003f; + k1x_pcie_conf0_reg_writel(k1x, 0, val); + } + else + { + pcie_rcal = k1x_pcie_phy0_reg_readl(k1x, 0x21 << 2); + } + } + else + { + count = 0; + do { + rd_data = k1x_pcie_phy0_reg_readl(k1x, 0x21 * 4); + + if (count++ > 5000) + { + LOG_E("Read PCIe%d phy rd_data time out", 0); + break; + } + } while (((rd_data >> 10) & 0x1) == 0); + pcie_rcal = k1x_pcie_phy0_reg_readl(k1x, 0x21 << 2); + } + + k1x->pcie_rcal = pcie_rcal; + + /* Disable ltssm and phy */ + reg = k1x_pcie_readl(k1x, PCIECTRL_K1X_CONF_DEVICE_CMD); + reg &= ~0x7f; + k1x_pcie_writel(k1x, PCIECTRL_K1X_CONF_DEVICE_CMD, reg); + + /* Soft rstc */ + reg = k1x_pcie_readl(k1x, PCIE_CTRL_LOGIC); + reg |= 1 << 0; + k1x_pcie_writel(k1x, PCIE_CTRL_LOGIC, reg); + + rt_thread_mdelay(2); + + /* Soft no rstc */ + reg = k1x_pcie_readl(k1x, PCIE_CTRL_LOGIC); + reg &= ~(1 << 0); + k1x_pcie_writel(k1x, PCIE_CTRL_LOGIC, reg); + + reg = k1x_pcie_readl(k1x, PCIECTRL_K1X_CONF_DEVICE_CMD); + reg |= 0x3f; + k1x_pcie_writel(k1x, PCIECTRL_K1X_CONF_DEVICE_CMD, reg); + + rterm_force(k1x, pcie_rcal); + + val = k1x_pcie_readl(k1x, PCIECTRL_K1X_CONF_DEVICE_CMD); + val &= 0xbfffffff; + k1x_pcie_writel(k1x, PCIECTRL_K1X_CONF_DEVICE_CMD, val); + + /* Set refclk model */ + val = k1x_pcie_phy_reg_readl(k1x, 0x17 << 2); + val |= 0x1 << 10; + k1x_pcie_phy_reg_writel(k1x, 0x17 << 2, val); + + val = k1x_pcie_phy_reg_readl(k1x, 0x17 << 2); + val &= ~(0x3 << 8); + k1x_pcie_phy_reg_writel(k1x, 0x17 << 2, val); + + val = k1x_pcie_phy_reg_readl(k1x, 0x400 + (0x17 << 2)); + val |= 0x1 << 10; + k1x_pcie_phy_reg_writel(k1x, 0x400 + (0x17 << 2), val); + + val = k1x_pcie_phy_reg_readl(k1x, 0x400 + (0x17 << 2)); + val &= ~(0x3 << 8); + k1x_pcie_phy_reg_writel(k1x, 0x400 + (0x17 << 2), val); + + /* Driver mode */ + val = k1x_pcie_phy_reg_readl(k1x, 0x17 << 2); + val |= 0x1 << 8; + k1x_pcie_phy_reg_writel(k1x, 0x17 << 2, val); + + val = k1x_pcie_phy_reg_readl(k1x, 0x400 + (0x17 << 2)); + val |= 0x1 << 8; + k1x_pcie_phy_reg_writel(k1x, 0x400 + (0x17 << 2), val); + + val = k1x_pcie_phy_reg_readl(k1x, 0x12 << 2); + val &= 0xffff0fff; + k1x_pcie_phy_reg_writel(k1x, 0x12 << 2, val); + + val = k1x_pcie_phy_reg_readl(k1x, 0x12 << 2); + val |= 0x00002000; + k1x_pcie_phy_reg_writel(k1x, 0x12 << 2, val); + + val = k1x_pcie_phy_reg_readl(k1x, 0x13 << 2); + val |= 0x1 << 4; + k1x_pcie_phy_reg_writel(k1x, 0x13 << 2, val); + + if (k1x->port_id == 0) + { + val = k1x_pcie_phy0_reg_readl(k1x, 0x14 << 2); + val |= 0x1 << 3; + k1x_pcie_phy0_reg_writel(k1x, 0x14 << 2, val); + } + + /* pll_reg1 of lane0, disable ssc pll_reg4[3:0]=4'h0 */ + val = k1x_pcie_phy_reg_readl(k1x, 0x12 << 2); + val &= 0xfff0ffff; + k1x_pcie_phy_reg_writel(k1x, 0x12 << 2, val); + + /* PU_ADDR_CLK_CFG of lane0 */ + k1x_pcie_phy_reg_writel(k1x, 0x02 << 2, 0x00000b78); + + /* PU_ADDR_CLK_CFG of lane1 */ + k1x_pcie_phy_reg_writel(k1x, 0x400 + (0x02 << 2), 0x00000b78); + + /* Force rcv done */ + k1x_pcie_phy_reg_writel(k1x, 0x06 << 2, 0x00000400); + + /* Waiting pll lock */ + do { + rd_data = k1x_pcie_phy_reg_readl(k1x, 0x8); + + if (count++ > 5000) + { + LOG_E("Read PCIe%d phy rd_data time out", k1x->port_id); + break; + } + } while ((rd_data & 0x1) == 0); + + if (k1x->port_id == 0) + { + porta_init_done = RT_TRUE; + } + + return RT_EOK; +} + +static void k1x_pcie_hold_phy_rst(struct k1x_pcie *k1x) +{ + rt_uint32_t reg; + + reg = k1x_pcie_readl(k1x, PCIECTRL_K1X_CONF_DEVICE_CMD); + + if (reg & APP_HOLD_PHY_RST) + { + LOG_D("Phy reset already held"); + return; + } + + reg |= APP_HOLD_PHY_RST; + k1x_pcie_writel(k1x, PCIECTRL_K1X_CONF_DEVICE_CMD, reg); +} + +#ifdef RT_USING_PM +static rt_err_t k1x_pcie_dw_pcie_pm_suspend(const struct rt_device *device, rt_uint8_t mode) +{ + rt_uint32_t val; + struct k1x_pcie *k1x = device->user_data; + struct dw_pcie *pci = &k1x->pci; + + if (k1x->mode != DW_PCIE_RC_TYPE) + { + return RT_EOK; + } + + /* Clear MSE */ + val = dw_pcie_readl_dbi(pci, PCIR_COMMAND); + val &= ~PCIM_CMD_MEMEN; + dw_pcie_writel_dbi(pci, PCIR_COMMAND, val); + + return RT_EOK; +} + +static void k1x_pcie_dw_pcie_pm_resume(const struct rt_device *device, rt_uint8_t mode) +{ + rt_uint32_t val; + struct k1x_pcie *k1x = device->user_data; + struct dw_pcie *pci = &k1x->pci; + + if (k1x->mode != DW_PCIE_RC_TYPE) + { + return; + } + + /* Set MSE */ + val = dw_pcie_readl_dbi(pci, PCIR_COMMAND); + val |= PCIM_CMD_MEMEN; + dw_pcie_writel_dbi(pci, PCIR_COMMAND, val); +} + +static const struct rt_device_pm_ops k1x_pcie_dw_pcie_pm_ops = +{ + .suspend = k1x_pcie_dw_pcie_pm_suspend, + .resume = k1x_pcie_dw_pcie_pm_resume, +}; +#endif /* RT_USING_PM */ + +static rt_err_t k1x_pcie_dw_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + rt_uint32_t reg; + struct dw_pcie *pci; + struct rt_device *dev = &pdev->parent; + struct k1x_pcie *k1x = rt_calloc(1, sizeof(*k1x)); + const struct k1x_pcie_soc_data *data = pdev->id->data; + + if (!k1x) + { + return -RT_ENOMEM; + } + k1x->mode = data->mode; + + pci = &k1x->pci; + pci->dev = dev; + pci->ops = &dw_pcie_ops; + pci->priv = k1x; + + if (!(k1x->base = rt_dm_dev_iomap_by_name(dev, "k1x_conf"))) + { + err = -RT_EIO; + goto _fail; + } + + if (!(k1x->phy_ahb = rt_dm_dev_iomap_by_name(dev, "phy_ahb"))) + { + err = -RT_EIO; + goto _fail; + } + + if (!(k1x->phy_addr = rt_dm_dev_iomap_by_name(dev, "phy_addr"))) + { + err = -RT_EIO; + goto _fail; + } + + if (!(k1x->conf0_addr = rt_dm_dev_iomap_by_name(dev, "conf0_addr"))) + { + err = -RT_EIO; + goto _fail; + } + + if (!(k1x->phy0_addr = rt_dm_dev_iomap_by_name(dev, "phy0_addr"))) + { + err = -RT_EIO; + goto _fail; + } + + if ((k1x->irq = rt_dm_dev_get_irq(dev, 1)) < 0) + { + err = k1x->irq; + goto _fail; + } + + if ((err = rt_dm_dev_prop_read_u32(dev, "k1x,pcie-port", &k1x->port_id))) + { + LOG_E("Failed to get pcie's port id"); + goto _fail; + } + + if (rt_dm_dev_prop_read_u32(dev, "num-lanes", &k1x->num_lanes)) + { + LOG_W("Failed to get pcie's port num-lanes"); + k1x->num_lanes = 1; + } + + if (k1x->num_lanes < 1 || k1x->num_lanes > 2) + { + LOG_W("Configuration of num-lanes is invalid"); + k1x->num_lanes = 1; + } + + k1x->pwr_on_pin = rt_pin_get_named_pin(dev, "k1x,pwr_on", 0, + RT_NULL, &k1x->pwr_on_active_val); + + k1x->clk_master = rt_clk_get_by_index(dev, 0); + if (rt_is_err(k1x->clk_master)) + { + err = rt_ptr_err(k1x->clk_master); + goto _fail; + } + + if ((err = rt_clk_prepare_enable(k1x->clk_master))) + { + goto _fail; + } + + /* PCIE0 and usb use combo phy and rstc */ + k1x->rstc = rt_reset_control_get_by_index(dev, 0); + if (rt_is_err(k1x->rstc)) + { + err = rt_ptr_err(k1x->rstc); + goto _fail; + } + + k1x_pcie_hold_phy_rst(k1x); + + rt_reset_control_deassert(k1x->rstc); + + if ((err = init_phy(k1x))) + { + goto _fail; + } + + if ((err = rt_dm_dev_prop_read_u32(dev, "max-link-speed", &k1x->link_gen))) + { + goto _fail; + } + if (k1x->link_gen < 0 || k1x->link_gen > 3) + { + k1x->link_gen = 3; + } + + rt_hw_interrupt_install(k1x->irq, k1x_pcie_isr, k1x, "k1x-pcie-vs"); + rt_hw_interrupt_umask(k1x->irq); + + switch (k1x->mode) + { + case DW_PCIE_RC_TYPE: + reg = k1x_pcie_readl(k1x, PCIECTRL_K1X_CONF_DEVICE_CMD); + reg |= DEVICE_TYPE_RC | PCIE_AUX_PWR_DET; + k1x_pcie_writel(k1x, PCIECTRL_K1X_CONF_DEVICE_CMD, reg); + + reg = k1x_pcie_readl(k1x, PCIE_CTRL_LOGIC); + reg |= PCIE_IGNORE_PERSTN; + k1x_pcie_writel(k1x, PCIE_CTRL_LOGIC, reg); + + /* Power on the interface */ + if (k1x->pwr_on_pin >= 0) + { + rt_pin_write(k1x->pwr_on_pin, k1x->pwr_on_active_val); + rt_pin_mode(k1x->pwr_on_pin, PIN_MODE_OUTPUT); + } + + err = k1x_add_pcie_port(k1x, dev); + break; + + case DW_PCIE_EP_TYPE: + reg = k1x_pcie_readl(k1x, PCIECTRL_K1X_CONF_DEVICE_CMD); + reg &= ~DEVICE_TYPE_RC; + k1x_pcie_writel(k1x, PCIECTRL_K1X_CONF_DEVICE_CMD, reg); + + err = k1x_add_pcie_ep(k1x, dev); + break; + + default: + /* It's impossible */ + RT_ASSERT(0); + break; + } + + if (err) + { + goto _free_irq; + } + +#ifdef RT_USING_PM + rt_pm_device_register(dev, &k1x_pcie_dw_pcie_pm_ops); +#endif + + dev->user_data = k1x; + + return RT_EOK; + +_free_irq: + rt_hw_interrupt_mask(k1x->irq); + rt_pic_detach_irq(k1x->irq, k1x); + + rt_clk_disable_unprepare(k1x->clk_master); + +_fail: + if (k1x->base) + { + rt_iounmap(k1x->base); + } + if (k1x->phy_ahb) + { + rt_iounmap(k1x->phy_ahb); + } + if (k1x->phy_addr) + { + rt_iounmap(k1x->phy_addr); + } + if (k1x->conf0_addr) + { + rt_iounmap(k1x->conf0_addr); + } + if (k1x->phy0_addr) + { + rt_iounmap(k1x->phy0_addr); + } + if (!rt_is_err_or_null(k1x->clk_master)) + { + rt_clk_put(k1x->clk_master); + } + if (!rt_is_err_or_null(k1x->rstc)) + { + rt_reset_control_put(k1x->rstc); + } + if (k1x->pci.port.msi_data) + { + rt_dma_free_coherent(dev, sizeof(rt_uint64_t), k1x->pci.port.msi_data, k1x->pci.port.msi_data_phy); + } + if (k1x->msix_data) + { + rt_dma_free_coherent(dev, sizeof(rt_uint64_t), k1x->msix_data, k1x->msix_data_phy); + } + + rt_free(k1x); + + return err; +} + +static const struct k1x_pcie_soc_data k1x_pcie_rc_soc_data = +{ + .mode = DW_PCIE_RC_TYPE, +}; + +static const struct k1x_pcie_soc_data k1x_pcie_ep_soc_data = +{ + .mode = DW_PCIE_EP_TYPE, +}; + +static const struct rt_ofw_node_id k1x_pcie_dw_ofw_ids[] = +{ + { .compatible = "k1x,dwc-pcie", .data = &k1x_pcie_rc_soc_data, }, + { .compatible = "k1x,dwc-pcie-ep", .data = &k1x_pcie_ep_soc_data, }, + { /* sentinel */ } +}; + +static struct rt_platform_driver k1x_pcie_dw_driver = +{ + .name = "dw-pcie-k1x", + .ids = k1x_pcie_dw_ofw_ids, + + .probe = k1x_pcie_dw_probe, +}; +RT_PLATFORM_DRIVER_EXPORT(k1x_pcie_dw_driver); diff --git a/bsp/spacemit/dm/pin/Kconfig b/bsp/spacemit/dm/pin/Kconfig new file mode 100644 index 000000000000..b4a0fbd0fcfa --- /dev/null +++ b/bsp/spacemit/dm/pin/Kconfig @@ -0,0 +1,5 @@ +config RT_PIN_K1X + bool "Spacemit K1X GPIO GPIO support" + depends on RT_USING_OFW + depends on RT_USING_ADT_BITMAP + default y diff --git a/bsp/spacemit/dm/pin/SConscript b/bsp/spacemit/dm/pin/SConscript new file mode 100644 index 000000000000..b91f5b9d9cc8 --- /dev/null +++ b/bsp/spacemit/dm/pin/SConscript @@ -0,0 +1,13 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include', cwd + '/../../../../components/drivers/pin'] + +if GetDepend(['RT_PIN_K1X']): + src += ['pin-k1x.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/pin/pin-k1x.c b/bsp/spacemit/dm/pin/pin-k1x.c new file mode 100644 index 000000000000..b7ff6235ed29 --- /dev/null +++ b/bsp/spacemit/dm/pin/pin-k1x.c @@ -0,0 +1,421 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include +#include +#include + +#define DBG_TAG "pin.k1" +#define DBG_LVL DBG_INFO +#include + +#include "dev_pin_dm.h" + +#define GPLR 0x0 +#define GPDR 0xc +#define GPSR 0x18 +#define GPCR 0x24 +#define GRER 0x30 +#define GFER 0x3c +#define GEDR 0x48 +#define GSDR 0x54 +#define GCDR 0x60 +#define GSRER 0x6c +#define GCRER 0x78 +#define GSFER 0x84 +#define GCFER 0x90 +#define GAPMASK 0x9c +#define GCPMASK 0xa8 + +#define K1X_BANK_GPIO_NUMBER 32 +#define BANK_GPIO_MASK (K1X_BANK_GPIO_NUMBER - 1) + +#define k1x_gpio_to_bank_idx(gpio) ((gpio) / K1X_BANK_GPIO_NUMBER) +#define k1x_gpio_to_bank_offset(gpio) ((gpio) & BANK_GPIO_MASK) + +struct k1x_gpio_bank +{ + void *reg_bank; + rt_uint32_t irq_mask; + rt_uint32_t irq_rising_edge; + rt_uint32_t irq_falling_edge; + + RT_BITMAP_DECLARE(value, K1X_BANK_GPIO_NUMBER); +}; + +struct k1x_gpio_chip +{ + struct rt_device_pin parent; + + int irq; + void *reg_base; + + unsigned int nbank; + struct k1x_gpio_bank *banks; +}; + +#define raw_to_k1x_gpio_chip(raw) rt_container_of(raw, struct k1x_gpio_chip, parent) + +static void k1x_pin_mode(struct rt_device *device, rt_base_t pin, rt_uint8_t mode) +{ + rt_uint32_t bit, offset; + struct k1x_gpio_chip *k1x_chip = raw_to_k1x_gpio_chip(device); + struct k1x_gpio_bank *bank = &k1x_chip->banks[k1x_gpio_to_bank_idx(pin)]; + + offset = k1x_gpio_to_bank_offset(pin); + bit = RT_BIT(offset); + + switch (mode) + { + case PIN_MODE_OUTPUT: + case PIN_MODE_OUTPUT_OD: + HWREG32(bank->reg_bank + (rt_bitmap_test_bit(bank->value, offset) ? GPSR : GPCR)) = bit; + HWREG32(bank->reg_bank + GSDR) = bit; + break; + + case PIN_MODE_INPUT: + case PIN_MODE_INPUT_PULLUP: + case PIN_MODE_INPUT_PULLDOWN: + HWREG32(bank->reg_bank + GCDR) = bit; + break; + + default: + break; + } +} + +static void k1x_pin_write(struct rt_device *device, rt_base_t pin, rt_uint8_t value) +{ + rt_uint32_t bit, offset, reg; + struct k1x_gpio_chip *k1x_chip = raw_to_k1x_gpio_chip(device); + struct k1x_gpio_bank *bank = &k1x_chip->banks[k1x_gpio_to_bank_idx(pin)]; + + offset = k1x_gpio_to_bank_offset(pin); + bit = RT_BIT(offset); + + if (HWREG32(bank->reg_bank + GPDR) & bit) + { + if (value) + { + reg = GPSR; + rt_bitmap_set_bit(bank->value, offset); + } + else + { + reg = GPCR; + rt_bitmap_clear_bit(bank->value, offset); + } + + HWREG32(bank->reg_bank + reg) = bit; + } +} + +static rt_ssize_t k1x_pin_read(struct rt_device *device, rt_base_t pin) +{ + rt_uint32_t bit; + struct k1x_gpio_chip *k1x_chip = raw_to_k1x_gpio_chip(device); + struct k1x_gpio_bank *bank = &k1x_chip->banks[k1x_gpio_to_bank_idx(pin)]; + + bit = RT_BIT(k1x_gpio_to_bank_offset(pin)); + + return !!(HWREG32(bank->reg_bank + GPLR) & bit); +} + +static rt_err_t k1x_pin_irq_enable(struct rt_device *device, rt_base_t pin, rt_uint8_t enabled) +{ + rt_uint32_t bit; + struct k1x_gpio_chip *k1x_chip = raw_to_k1x_gpio_chip(device); + struct k1x_gpio_bank *bank = &k1x_chip->banks[k1x_gpio_to_bank_idx(pin)]; + + bit = RT_BIT(k1x_gpio_to_bank_offset(pin)); + + if (enabled) + { + bank->irq_mask |= bit; + + /* Set the bit of rising and falling edge detection if the gpio has. */ + HWREG32(bank->reg_bank + GSRER) = bit & bank->irq_rising_edge; + HWREG32(bank->reg_bank + GSFER) = bit & bank->irq_falling_edge; + } + else + { + bank->irq_mask &= ~bit; + + /* Clear the bit of rising and falling edge detection. */ + HWREG32(bank->reg_bank + GCRER) = bit; + HWREG32(bank->reg_bank + GCFER) = bit; + } + + return RT_EOK; +} + +static rt_err_t k1x_pin_irq_mode(struct rt_device *device, rt_base_t pin, rt_uint8_t mode) +{ + rt_uint32_t bit; + struct k1x_gpio_chip *k1x_chip = raw_to_k1x_gpio_chip(device); + struct k1x_gpio_bank *bank = &k1x_chip->banks[k1x_gpio_to_bank_idx(pin)]; + + bit = RT_BIT(k1x_gpio_to_bank_offset(pin)); + + if (mode == PIN_IRQ_MODE_RISING) + { + bank->irq_rising_edge |= bit; + HWREG32(bank->reg_bank + GSRER) = bit; + } + else + { + bank->irq_rising_edge &= ~bit; + HWREG32(bank->reg_bank + GCRER) = bit; + } + + if (mode == PIN_IRQ_MODE_FALLING) + { + bank->irq_falling_edge |= bit; + HWREG32(bank->reg_bank + GSFER) = bit; + } + else + { + bank->irq_falling_edge &= ~bit; + HWREG32(bank->reg_bank + GCFER) = bit; + } + + return RT_EOK; +} + +static rt_ssize_t k1x_pin_parse(struct rt_device *device, + struct rt_ofw_cell_args *args, rt_uint32_t *flags) +{ + rt_base_t gpio_pin; + rt_err_t err = RT_EOK; + + if (flags) + { + *flags = args->args[1]; + } + + gpio_pin = args->args[0]; + + for (int i = 0;; ++i) + { + rt_base_t gpio_start, pad_start; + struct rt_device_pin *pinctrl; + struct rt_ofw_cell_args gpio_ranges; + + if (rt_ofw_parse_phandle_cells(device->ofw_node, "gpio-ranges", + "#gpio-range-cells", i, &gpio_ranges)) + { + break; + } + + gpio_start = gpio_ranges.args[0]; + pad_start = gpio_ranges.args[1]; + + if (gpio_pin < gpio_start || gpio_pin > gpio_start + gpio_ranges.args[2]) + { + rt_ofw_node_put(gpio_ranges.data); + continue; + } + + if (!(pinctrl = rt_ofw_data(gpio_ranges.data))) + { + err = -RT_EIO; + goto _end; + } + + err = pin_gpio_request(pinctrl, pad_start + (gpio_pin - gpio_start), args->args[1]); + + _end: + rt_ofw_node_put(gpio_ranges.data); + + break; + } + + return err ? : gpio_pin; +} + +static const struct rt_pin_ops k1x_pin_ops = +{ + .pin_mode = k1x_pin_mode, + .pin_write = k1x_pin_write, + .pin_read = k1x_pin_read, + .pin_irq_enable = k1x_pin_irq_enable, + .pin_irq_mode = k1x_pin_irq_mode, + .pin_parse = k1x_pin_parse, +}; + +static void k1x_gpio_isr(int irqno, void *param) +{ + int n; + rt_uint32_t gedr; + rt_bitmap_t pending; + struct k1x_gpio_bank *bank; + struct k1x_gpio_chip *k1x_chip = param; + + for (int i = 0; i < k1x_chip->nbank; ++i) + { + bank = &k1x_chip->banks[i]; + + gedr = HWREG32(bank->reg_bank + GEDR); + if (!gedr) + { + continue; + } + + HWREG32(bank->reg_bank + GEDR) = gedr; + gedr = gedr & bank->irq_mask; + + if (!gedr) + { + continue; + } + pending = gedr; + + rt_bitmap_for_each_set_bit(&pending, n, RT_BITS_PER_LONG) + { + rt_base_t pin = (i * K1X_BANK_GPIO_NUMBER) | (n & BANK_GPIO_MASK); + + HWREG32(bank->reg_bank + GEDR) = (1 << k1x_gpio_to_bank_offset(pin)); + + pin_pic_handle_isr(&k1x_chip->parent, pin); + } + } +} + +static rt_err_t k1x_gpio_probe(struct rt_platform_device *pdev) +{ + int i = 0; + rt_err_t err; + const char *name; + struct rt_clk *clk = RT_NULL; + struct rt_device *dev = &pdev->parent; + struct rt_ofw_node *np = dev->ofw_node, *child; + struct k1x_gpio_bank *bank; + struct k1x_gpio_chip *k1x_chip = rt_calloc(1, sizeof(*k1x_chip)); + + if (!k1x_chip) + { + return -RT_ENOMEM; + } + + if (!(k1x_chip->reg_base = rt_dm_dev_iomap(dev, 0))) + { + err = -RT_EIO; + goto _fail; + } + + if ((k1x_chip->irq = rt_dm_dev_get_irq(dev, 0)) < 0) + { + err = k1x_chip->irq; + goto _fail; + } + + k1x_chip->nbank = rt_ofw_get_child_count(np); + k1x_chip->banks = rt_calloc(k1x_chip->nbank, sizeof(*k1x_chip->banks)); + + if (!k1x_chip->banks) + { + err = -RT_ENOMEM; + goto _fail; + } + + rt_ofw_foreach_child_node(np, child) + { + rt_uint32_t offset; + + if ((err = rt_ofw_prop_read_u32(child, "reg-offset", &offset))) + { + rt_ofw_node_put(child); + goto _fail; + } + + k1x_chip->banks[i++].reg_bank = k1x_chip->reg_base + offset; + } + + clk = rt_clk_get_by_index(dev, 0); + if (rt_is_err(clk)) + { + err = rt_ptr_err(clk); + goto _fail; + } + + if ((err = rt_clk_prepare_enable(clk))) + { + LOG_E("Fail to enable gpio clock"); + goto _fail; + } + + rt_dm_dev_set_name_auto(&k1x_chip->parent.parent, "gpio"); + name = rt_dm_dev_get_name(&k1x_chip->parent.parent); + + rt_hw_interrupt_install(k1x_chip->irq, k1x_gpio_isr, k1x_chip, name); + rt_hw_interrupt_umask(k1x_chip->irq); + + k1x_chip->parent.ops = &k1x_pin_ops; + k1x_chip->parent.parent.ofw_node = np; + pin_api_init(&k1x_chip->parent, k1x_chip->nbank * K1X_BANK_GPIO_NUMBER); + pin_pic_init(&k1x_chip->parent, k1x_chip->irq); + + rt_ofw_data(np) = &k1x_chip->parent; + + /* Clear all GPIO edge detects */ + for (i = 0; i < k1x_chip->nbank; ++i) + { + bank = &k1x_chip->banks[i]; + HWREG32(bank->reg_bank + GCFER) = 0xffffffff; + HWREG32(bank->reg_bank + GCRER) = 0xffffffff; + /* Unmask edge detection to AP. */ + HWREG32(bank->reg_bank + GAPMASK) = 0xffffffff; + } + + return RT_EOK; +_fail: + if (!rt_is_err_or_null(clk)) + { + rt_clk_disable_unprepare(clk); + rt_clk_put(clk); + } + + if (k1x_chip->reg_base) + { + rt_iounmap(k1x_chip->reg_base); + } + + if (k1x_chip->banks) + { + rt_free(k1x_chip->banks); + } + + rt_free(k1x_chip); + + return err; +} + +static const struct rt_ofw_node_id k1x_gpio_ofw_ids[] = +{ + { .compatible = "spacemit,k1x-gpio" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver k1x_gpio_driver = +{ + .name = "k1x-gpio", + .ids = k1x_gpio_ofw_ids, + + .probe = k1x_gpio_probe, +}; + +static int k1x_gpio_register(void) +{ + rt_platform_driver_register(&k1x_gpio_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(k1x_gpio_register); diff --git a/bsp/spacemit/dm/pinctrl/Kconfig b/bsp/spacemit/dm/pinctrl/Kconfig new file mode 100644 index 000000000000..4b2512a158f1 --- /dev/null +++ b/bsp/spacemit/dm/pinctrl/Kconfig @@ -0,0 +1,5 @@ +config RT_PINCTRL_SPACEMIT_PMIC + bool "Pinctrl and GPIO driver for Spacemit PMIC" + depends on RT_USING_PINCTRL + depends on RT_MFD_SPACEMIT_PMIC + default n diff --git a/bsp/spacemit/dm/pinctrl/SConscript b/bsp/spacemit/dm/pinctrl/SConscript new file mode 100644 index 000000000000..1f89d5044006 --- /dev/null +++ b/bsp/spacemit/dm/pinctrl/SConscript @@ -0,0 +1,13 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_PINCTRL_SPACEMIT_PMIC']): + src += ['spacemit-pmic-pinctrl.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/pinctrl/spacemit-pmic-pinctrl.c b/bsp/spacemit/dm/pinctrl/spacemit-pmic-pinctrl.c new file mode 100644 index 000000000000..b546b894b0cd --- /dev/null +++ b/bsp/spacemit/dm/pinctrl/spacemit-pmic-pinctrl.c @@ -0,0 +1,364 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include + +#define DBG_TAG "pinctrl.spacemit-pmic" +#define DBG_LVL DBG_INFO +#include + +#define __SPACEMIT_PINCTRL_INTERNAL +#include + +struct spacemit_pmic_pinctrl +{ + struct rt_device_pin parent; + + rt_uint32_t npins; + + struct spacemit_pmic *pmic; + const struct spacemit_pmic_pin_data *data; +}; + +#define raw_to_spacemit_pmic_pinctrl(raw) rt_container_of(raw, struct spacemit_pmic_pinctrl, parent) + +static rt_err_t spacemit_pmic_pinctrl_set_mux(struct spacemit_pmic_pinctrl *pmic_pinctrl, + rt_uint32_t function, rt_base_t pin) +{ + int i; + rt_err_t err; + const char *funcname; + struct spacemit_pmic *pmic = pmic_pinctrl->pmic; + const struct spacemit_pmic_pin_data *data = pmic_pinctrl->data; + const struct spacemit_pmic_pin_func_desc *pinfunc_desc = data->pinfunc_desc; + + funcname = data->pinmux_funcs[function]; + + for (i = 0; i < data->pin_mux_nr; ++i) + { + if (!rt_strcmp(funcname, pinfunc_desc[i].name) && pin == pinfunc_desc[i].pin_id) + { + /* Set the first */ + err = spacemit_pmic_update_bits(pmic, + pinfunc_desc[i].func_reg, + pinfunc_desc[i].func_mask, + pinfunc_desc[i].en_val << (__rt_ffs(pinfunc_desc[i].func_mask) - 1)); + if (err) + { + LOG_E("Set PIN%d, function:%s, failed", pin, funcname); + return err; + } + + /* Set the next if it have */ + if (pinfunc_desc[i].ha_sub) + { + err = spacemit_pmic_update_bits(pmic, + pinfunc_desc[i].sub_reg, + pinfunc_desc[i].sub_mask, + pinfunc_desc[i].sube_val << (__rt_ffs(pinfunc_desc[i].sub_mask) - 1)); + if (err) + { + LOG_E("Set PIN%d, function:%s, failed", pin, funcname); + return err; + } + } + + break; + } + } + + if (i >= data->pin_mux_nr) + { + LOG_E("Unsupported PIN%d, function:%s", pin, funcname); + return -RT_EINVAL; + } + + return RT_EOK; +} + +static void spacemit_pmic_pinctrl_mode(struct rt_device *device, rt_base_t pin, rt_uint8_t mode) +{ + struct spacemit_pmic_pinctrl *pmic_pinctrl = raw_to_spacemit_pmic_pinctrl(device); + + switch (mode) + { + case PIN_MODE_OUTPUT: + spacemit_pmic_pinctrl_set_mux(pmic_pinctrl, 1, pin); + break; + + case PIN_MODE_INPUT: + spacemit_pmic_pinctrl_set_mux(pmic_pinctrl, 0, pin); + break; + + default: + break; + } +} + +static void spacemit_pmic_pinctrl_write(struct rt_device *device, rt_base_t pin, + rt_uint8_t value) +{ + rt_err_t err; + const struct spacemit_pmic_pin_config_desc *pinconf_desc; + struct spacemit_pmic_pinctrl *pmic_pinctrl = raw_to_spacemit_pmic_pinctrl(device); + + pinconf_desc = pmic_pinctrl->data->pinconf_desc; + + err = spacemit_pmic_update_bits(pmic_pinctrl->pmic, + pinconf_desc[pin].output.reg, + pinconf_desc[pin].output.msk, + value ? pinconf_desc[pin].output.msk : 0); + + if (err) + { + LOG_E("Set PIN%d, val:%d, failed", pin, value); + } +} + +static rt_ssize_t spacemit_pmic_pinctrl_read(struct rt_device *device, rt_base_t pin) +{ + rt_ssize_t val; + const struct spacemit_pmic_pin_config_desc *pinconf_desc; + struct spacemit_pmic_pinctrl *pmic_pinctrl = raw_to_spacemit_pmic_pinctrl(device); + + pinconf_desc = pmic_pinctrl->data->pinconf_desc; + + if ((val = spacemit_pmic_read(pmic_pinctrl->pmic, pinconf_desc[pin].input.reg)) < 0) + { + LOG_E("Get PIN%d, direction failed", pin); + return val; + } + + val = val & pinconf_desc[pin].input.msk; + val >>= __rt_ffs(pinconf_desc[pin].input.msk) - 1; + + return val; +} + +static rt_ssize_t spacemit_pmic_pin_parse(struct rt_device *device, + struct rt_ofw_cell_args *args, rt_uint32_t *flags) +{ + if (flags) + { + *flags = args->args[1]; + } + + return args->args[0]; +} + +static const struct rt_pin_ctrl_conf_params spacemit_pmic_pinctrl_params[] = +{ + { "bias-disable", PIN_CONFIG_BIAS_DISABLE }, + { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN }, + { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP }, + { "drive-open-drain", PIN_CONFIG_DRIVE_OPEN_DRAIN }, + { "drive-push-pull", PIN_CONFIG_DRIVE_PUSH_PULL }, + { "drive-open-source", PIN_CONFIG_DRIVE_OPEN_SOURCE }, + { "input-debounce", PIN_CONFIG_INPUT_DEBOUNCE }, + { "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE }, + { "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE }, + { "output-high", PIN_CONFIG_OUTPUT }, + { "output-low", PIN_CONFIG_OUTPUT }, +}; + +static rt_bool_t spacemit_pmic_pinctrl_param_parse(const char *name, rt_uint32_t *out_param) +{ + for (int i = 0; i < RT_ARRAY_SIZE(spacemit_pmic_pinctrl_params); ++i) + { + if (!rt_strcmp(spacemit_pmic_pinctrl_params[i].propname, name)) + { + *out_param = spacemit_pmic_pinctrl_params[i].param; + return RT_TRUE; + } + } + + return RT_FALSE; +} + +static rt_err_t spacemit_pmic_pinctrl_confs_apply(struct rt_device *device, void *fw_conf_np) +{ + rt_err_t err; + rt_ubase_t pin; + rt_uint32_t function, param; + const char *string; + struct rt_ofw_prop *pins_prop, *prop; + struct spacemit_pmic_pinctrl *pmic_pinctrl = raw_to_spacemit_pmic_pinctrl(device); + const struct spacemit_pmic_pin_data *data = pmic_pinctrl->data; + const struct spacemit_pmic_pin_config_desc *pinconf_desc = data->pinconf_desc; + struct spacemit_pmic *pmic = pmic_pinctrl->pmic; + + /** + * led_pins: led-pins { + * pins = "PIN3"; + * function = "sleep"; + * bias-disable = <0>; + * drive-open-drain = <0x1>; + * }; + */ + + if ((err = rt_ofw_prop_read_string(fw_conf_np, "function", &string))) + { + return err; + } + + function = data->pin_mux_nr; + + for (int i = 0; i < data->pin_mux_nr; ++i) + { + if (!rt_strcmp(data->pinmux_funcs[i], string)) + { + function = i; + } + } + + if (function >= data->pin_mux_nr) + { + return -RT_EINVAL; + } + + rt_ofw_foreach_prop_string(fw_conf_np, "pins", pins_prop, string) + { + pin = 0; + string += sizeof("PIN") - 1; + + while (*string) + { + pin *= 10; + pin += *string - '0'; + + ++string; + } + + if (spacemit_pmic_pinctrl_set_mux(pmic_pinctrl, function, pin)) + { + return err; + } + + rt_ofw_foreach_prop(((struct rt_ofw_node *)fw_conf_np), prop) + { + rt_uint32_t reg, msk; + + if (!rt_strcmp(prop->name, "pins") || !rt_strcmp(prop->name, "function")) + { + continue; + } + + if (!spacemit_pmic_pinctrl_param_parse(prop->name, ¶m)) + { + return -RT_ENOSYS; + } + + switch (param) + { + case PIN_CONFIG_BIAS_DISABLE: + case PIN_CONFIG_BIAS_PULL_DOWN: + case PIN_CONFIG_BIAS_PULL_UP: + reg = pinconf_desc[pin].pup.reg; + msk = pinconf_desc[pin].pup.msk; + break; + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + case PIN_CONFIG_DRIVE_PUSH_PULL: + case PIN_CONFIG_DRIVE_OPEN_SOURCE: + reg = pinconf_desc[pin].od.reg; + msk = pinconf_desc[pin].od.msk; + break; + case PIN_CONFIG_INPUT_DEBOUNCE: + reg = pinconf_desc[pin].deb.reg; + msk = pinconf_desc[pin].deb.timemsk; + break; + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + reg = pinconf_desc[pin].deb.reg; + msk = pinconf_desc[pin].deb.en.msk; + break; + case PIN_CONFIG_OUTPUT: + reg = pinconf_desc[pin].output.reg; + msk = pinconf_desc[pin].output.msk; + break; + default: + LOG_E("To fixed your code"); + RT_ASSERT(0); + break; + } + + err = spacemit_pmic_update_bits(pmic, reg, msk, + fdt32_to_cpu(*(fdt32_t *)prop->value) << (__rt_ffs(msk) - 1)); + if (err) + { + LOG_E("Set reg:%x, msk:%x failed", reg, msk); + return -RT_EINVAL; + } + } + } + + return RT_EOK; +} + +static const struct rt_pin_ops spacemit_pmic_pinctrl_ops = +{ + .pin_mode = spacemit_pmic_pinctrl_mode, + .pin_write = spacemit_pmic_pinctrl_write, + .pin_read = spacemit_pmic_pinctrl_read, + .pin_parse = spacemit_pmic_pin_parse, + .pin_ctrl_confs_apply = spacemit_pmic_pinctrl_confs_apply, +}; + +static rt_err_t spacemit_pmic_pinctrl_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct spacemit_pmic *pmic = pdev->priv; + struct spacemit_pmic_pinctrl *pmic_pinctrl = rt_calloc(1, sizeof(*pmic_pinctrl)); + + if (!pmic_pinctrl) + { + return -RT_ENOMEM; + } + + pmic_pinctrl->pmic = pmic; + pmic_pinctrl->data = pdev->id->data; + + if ((err = rt_dm_dev_prop_read_u32(dev, "spacemit,npins", &pmic_pinctrl->npins))) + { + goto _fail; + } + + pmic_pinctrl->parent.ops = &spacemit_pmic_pinctrl_ops; + rt_ofw_data(dev->ofw_node) = &pmic_pinctrl->parent; + + return RT_EOK; + +_fail: + rt_free(pmic_pinctrl); + + return err; +} + +static const struct rt_ofw_node_id spacemit_pmic_pinctrl_ofw_ids[] = +{ + { .compatible = "pmic,pinctrl,spm8821", .data = &spm8821_pinctrl_data }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_pmic_pinctrl_driver = +{ + .name = "spacemit-pmic-pinctrl", + .ids = spacemit_pmic_pinctrl_ofw_ids, + + .probe = spacemit_pmic_pinctrl_probe, +}; + +static int spacemit_pmic_pinctrl_register(void) +{ + rt_platform_driver_register(&spacemit_pmic_pinctrl_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(spacemit_pmic_pinctrl_register); diff --git a/bsp/spacemit/dm/pmdomain/Kconfig b/bsp/spacemit/dm/pmdomain/Kconfig new file mode 100644 index 000000000000..fc0b03ed886d --- /dev/null +++ b/bsp/spacemit/dm/pmdomain/Kconfig @@ -0,0 +1,6 @@ +config RT_PMDOMAIN_K1X + bool "Spacemit k1x" + depends on RT_MFD_SYSCON + depends on RT_USING_CLK + depends on RT_USING_REGULATOR + default y diff --git a/bsp/spacemit/dm/pmdomain/SConscript b/bsp/spacemit/dm/pmdomain/SConscript new file mode 100644 index 000000000000..13765f24355c --- /dev/null +++ b/bsp/spacemit/dm/pmdomain/SConscript @@ -0,0 +1,12 @@ +from building import * + +cwd = GetCurrentDir() +src = [] +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_PMDOMAIN_K1X']): + src += ['pm-domain-k1x.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/pmdomain/pm-domain-k1x.c b/bsp/spacemit/dm/pmdomain/pm-domain-k1x.c new file mode 100644 index 000000000000..5f20d701ec5d --- /dev/null +++ b/bsp/spacemit/dm/pmdomain/pm-domain-k1x.c @@ -0,0 +1,582 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include +#include + +#include +#include + +#define DBG_TAG "pm-domain.spacemit.k1x" +#define DBG_LVL DBG_INFO +#include + +#define MAX_REGULATOR_PER_DOMAIN 5 + +#define APMU_POWER_STATUS_REG 0xf0 +#define MPMU_AWUCRM_REG 0x104c + +struct spacemit_pmu; + +struct spacemit_pm_domain_param +{ + rt_uint32_t reg_pwr_ctrl; + rt_uint32_t pm_qos; + rt_uint32_t bit_hw_mode; + rt_uint32_t bit_sleep2; + rt_uint32_t bit_sleep1; + rt_uint32_t bit_isolation; + rt_uint32_t bit_auto_pwr_on; + rt_uint32_t bit_hw_pwr_stat; + rt_uint32_t bit_pwr_stat; + rt_uint32_t use_hw; +}; + +struct spacemit_pm_domain +{ + struct rt_dm_power_domain parent; + + int index; + int supply_count; + int ref_handle_pm_domain; + struct spacemit_pmu *pmu; + struct rt_regulator *supply[MAX_REGULATOR_PER_DOMAIN]; + + struct spacemit_pm_domain_param param; +}; + +#define raw_to_spacemit_pm_domain(raw) rt_container_of(raw, struct spacemit_pm_domain, parent) + +struct spacemit_pmu +{ + struct rt_dm_power_domain_proxy parent; + + struct rt_syscon *mpmu_regmap; + struct rt_syscon *apmu_regmap; + + rt_uint32_t num_domains; + struct spacemit_pm_domain *domains; +}; + +#define raw_to_spacemit_pmu(raw) rt_container_of(raw, struct spacemit_pmu, parent) + +static rt_err_t spacemit_pd_power_on(struct rt_dm_power_domain *domain) +{ + int loop; + rt_err_t err; + rt_uint32_t val; + struct spacemit_pmu *pmu; + struct spacemit_pm_domain *spd = raw_to_spacemit_pm_domain(domain); + + if (spd->param.reg_pwr_ctrl == 0) + { + return RT_EOK; + } + + if (spd->ref_handle_pm_domain > 0) + { + return RT_EOK; + } + + /* Enable the supply */ + for (int loop = 0; loop < spd->supply_count; ++loop) + { + if ((err = rt_regulator_enable(spd->supply[loop])) && spd->supply[loop]) + { + return err; + } + } + + pmu = spd->pmu; + + rt_syscon_read(pmu->apmu_regmap, APMU_POWER_STATUS_REG, &val); + + if (val & (1 << spd->param.bit_pwr_stat)) + { + if (spd->index == K1X_PMU_LCD_PWR_DOMAIN) + { + return RT_EOK; + } + + if (!spd->param.use_hw) + { + /* This is the sw type */ + rt_syscon_read(pmu->apmu_regmap, spd->param.reg_pwr_ctrl, &val); + val &= ~(1 << spd->param.bit_isolation); + rt_syscon_write(pmu->apmu_regmap, spd->param.reg_pwr_ctrl, val); + + rt_hw_us_delay(12); + + /* MCU power off */ + rt_syscon_read(pmu->apmu_regmap, spd->param.reg_pwr_ctrl, &val); + val &= ~((1 << spd->param.bit_sleep1) | (1 << spd->param.bit_sleep2)); + rt_syscon_write(pmu->apmu_regmap, spd->param.reg_pwr_ctrl, val); + + rt_hw_us_delay(12); + + for (loop = 10000; loop >= 0; --loop) + { + rt_syscon_read(pmu->apmu_regmap, APMU_POWER_STATUS_REG, &val); + + if ((val & (1 << spd->param.bit_pwr_stat)) == 0) + { + break; + } + + rt_hw_us_delay(5); + } + } + else + { + /* LCD */ + rt_syscon_read(pmu->apmu_regmap, spd->param.reg_pwr_ctrl, &val); + val &= ~(1 << spd->param.bit_auto_pwr_on); + val &= ~(1 << spd->param.bit_hw_mode); + rt_syscon_write(pmu->apmu_regmap, spd->param.reg_pwr_ctrl, val); + + rt_hw_us_delay(20); + + for (loop = 10000; loop >= 0; --loop) + { + rt_syscon_read(pmu->apmu_regmap, APMU_POWER_STATUS_REG, &val); + + if ((val & (1 << spd->param.bit_hw_pwr_stat)) == 0) + { + break; + } + + rt_hw_us_delay(5); + } + } + + if (loop < 0) + { + LOG_E("Power on Domain(%d) fail", spd->index); + return -RT_EBUSY; + } + } + + if (!spd->param.use_hw) + { + /* mcu power on */ + rt_syscon_read(pmu->apmu_regmap, spd->param.reg_pwr_ctrl, &val); + val |= (1 << spd->param.bit_sleep1); + rt_syscon_write(pmu->apmu_regmap, spd->param.reg_pwr_ctrl, val); + + rt_hw_us_delay(22); + + rt_syscon_read(pmu->apmu_regmap, spd->param.reg_pwr_ctrl, &val); + val |= (1 << spd->param.bit_sleep2) | (1 << spd->param.bit_sleep1); + rt_syscon_write(pmu->apmu_regmap, spd->param.reg_pwr_ctrl, val); + + rt_hw_us_delay(22); + + /* disable isolation */ + rt_syscon_read(pmu->apmu_regmap, spd->param.reg_pwr_ctrl, &val); + val |= (1 << spd->param.bit_isolation); + rt_syscon_write(pmu->apmu_regmap, spd->param.reg_pwr_ctrl, val); + + rt_hw_us_delay(12); + + for (loop = 10000; loop >= 0; --loop) + { + rt_syscon_read(pmu->apmu_regmap, APMU_POWER_STATUS_REG, &val); + + if (val & (1 << spd->param.bit_pwr_stat)) + { + break; + } + + rt_hw_us_delay(5); + } + } + else + { + /* LCD */ + rt_syscon_read(pmu->apmu_regmap, spd->param.reg_pwr_ctrl, &val); + val |= (1 << spd->param.bit_auto_pwr_on); + val |= (1 << spd->param.bit_hw_mode); + rt_syscon_write(pmu->apmu_regmap, spd->param.reg_pwr_ctrl, val); + + rt_hw_us_delay(300); + + for (loop = 10000; loop >= 0; --loop) + { + rt_syscon_read(pmu->apmu_regmap, APMU_POWER_STATUS_REG, &val); + + if (val & (1 << spd->param.bit_hw_pwr_stat)) + { + break; + } + + rt_hw_us_delay(5); + } + } + + if (loop < 0) + { + LOG_E("Power on Domain(%d) fail", spd->index); + return -RT_EBUSY; + } + + return RT_EOK; +} + +static rt_err_t spacemit_pd_power_off(struct rt_dm_power_domain *domain) +{ + int loop; + rt_err_t err; + rt_uint32_t val; + struct spacemit_pmu *pmu; + struct spacemit_pm_domain *spd = raw_to_spacemit_pm_domain(domain); + + if (spd->param.reg_pwr_ctrl == 0) + { + return RT_EOK; + } + + if (spd->ref_handle_pm_domain > 0) + { + return RT_EOK; + } + + pmu = spd->pmu; + + if (!spd->param.use_hw) + { + /* this is the sw type */ + rt_syscon_read(pmu->apmu_regmap, spd->param.reg_pwr_ctrl, &val); + val &= ~(1 << spd->param.bit_isolation); + rt_syscon_write(pmu->apmu_regmap, spd->param.reg_pwr_ctrl, val); + + rt_hw_us_delay(12); + + /* mcu power off */ + rt_syscon_read(pmu->apmu_regmap, spd->param.reg_pwr_ctrl, &val); + val &= ~((1 << spd->param.bit_sleep1) | (1 << spd->param.bit_sleep2)); + rt_syscon_write(pmu->apmu_regmap, spd->param.reg_pwr_ctrl, val); + + rt_hw_us_delay(12); + + for (loop = 10000; loop >= 0; --loop) + { + rt_syscon_read(pmu->apmu_regmap, APMU_POWER_STATUS_REG, &val); + + if ((val & (1 << spd->param.bit_pwr_stat)) == 0) + { + break; + } + + rt_hw_us_delay(5); + } + } + else + { + /* LCD */ + rt_syscon_read(pmu->apmu_regmap, spd->param.reg_pwr_ctrl, &val); + val &= ~(1 << spd->param.bit_auto_pwr_on); + val &= ~(1 << spd->param.bit_hw_mode); + rt_syscon_write(pmu->apmu_regmap, spd->param.reg_pwr_ctrl, val); + + rt_hw_us_delay(20); + + for (loop = 10000; loop >= 0; --loop) + { + rt_syscon_read(pmu->apmu_regmap, APMU_POWER_STATUS_REG, &val); + + if ((val & (1 << spd->param.bit_hw_pwr_stat)) == 0) + { + break; + } + + rt_hw_us_delay(5); + } + } + + if (loop < 0) + { + LOG_E("Power off Domain(%d) fail", spd->index); + return -RT_EBUSY; + } + + /* enable the supply */ + for (loop = 0; loop < spd->supply_count; ++loop) + { + if ((err = rt_regulator_disable(spd->supply[loop])) && spd->supply[loop]) + { + return err; + } + } + + return RT_EOK; +} + +static rt_err_t spacemit_pd_attach_dev(struct rt_dm_power_domain *domain, + struct rt_device *dev) +{ + struct spacemit_pm_domain *spd = raw_to_spacemit_pm_domain(domain); + + if (rt_ofw_prop_read_bool(dev->ofw_node, "pwr-domain,pm-runtime,no-sleep")) + { + ++spd->ref_handle_pm_domain; + } + + return RT_EOK; +} + +static rt_err_t spacemit_pd_detach_dev(struct rt_dm_power_domain *domain, + struct rt_device *dev) +{ + struct spacemit_pm_domain *spd = raw_to_spacemit_pm_domain(domain); + + if (rt_ofw_prop_read_bool(dev->ofw_node, "pwr-domain,pm-runtime,no-sleep")) + { + --spd->ref_handle_pm_domain; + } + + return RT_EOK; +} + +static struct rt_dm_power_domain *spacemit_pmdomain_proxy_ofw_parse( + struct rt_dm_power_domain_proxy *proxy, struct rt_ofw_cell_args *args) +{ + struct spacemit_pmu *pmu = raw_to_spacemit_pmu(proxy); + + return &pmu->domains[args->args[0]].parent; +} + +static rt_err_t spacemit_pm_add_one_domain(struct spacemit_pmu *pmu, + struct rt_ofw_node *np) +{ + rt_err_t err; + rt_uint32_t idx; + struct rt_device dev; + struct spacemit_pm_domain *spd; + struct rt_dm_power_domain *domain; + const char *strings[MAX_REGULATOR_PER_DOMAIN]; + + if ((err = rt_ofw_prop_read_u32(np, "reg", &idx))) + { + LOG_E("Failed to read %s domain id (reg) error = %s", + rt_ofw_node_full_name(np), rt_strerror(err)); + return err; + } + + spd = &pmu->domains[idx]; + spd->index = idx; + + if ((err = rt_ofw_prop_read_u32(np, "pm_qos", &spd->param.pm_qos))) + { + return -RT_EINVAL; + } + + rt_ofw_prop_read_u32(np, "reg_pwr_ctrl", &spd->param.reg_pwr_ctrl); + rt_ofw_prop_read_u32(np, "bit_hw_mode", &spd->param.bit_hw_mode); + rt_ofw_prop_read_u32(np, "bit_sleep2", &spd->param.bit_sleep2); + rt_ofw_prop_read_u32(np, "bit_sleep1", &spd->param.bit_sleep1); + rt_ofw_prop_read_u32(np, "bit_isolation", &spd->param.bit_isolation); + rt_ofw_prop_read_u32(np, "bit_auto_pwr_on", &spd->param.bit_auto_pwr_on); + rt_ofw_prop_read_u32(np, "bit_hw_pwr_stat", &spd->param.bit_hw_pwr_stat); + rt_ofw_prop_read_u32(np, "bit_pwr_stat", &spd->param.bit_pwr_stat); + rt_ofw_prop_read_u32(np, "use_hw", &spd->param.use_hw); + + spd->supply_count = rt_ofw_prop_read_string_array_index(np, "vin-supply-names", + 0, RT_ARRAY_SIZE(strings), strings); + + if (spd->supply_count > 0) + { + dev.ofw_node = np; + + for (int i = 0; i < spd->supply_count; ++i) + { + spd->supply[i] = rt_regulator_get(&dev, strings[i]); + + if (rt_is_err(spd->supply[i])) + { + LOG_E("Regulator supply %s get failed", strings[i]); + return rt_ptr_err(spd->supply[i]); + } + } + } + else + { + spd->supply_count = 0; + } + + spd->pmu = pmu; + + domain = &spd->parent; + domain->power_on = spacemit_pd_power_on; + domain->power_off = spacemit_pd_power_off; + domain->attach_dev = spacemit_pd_attach_dev; + domain->detach_dev = spacemit_pd_detach_dev; + + if ((err = rt_dm_power_domain_register(domain))) + { + return err; + } + + rt_ofw_data(np) = domain; + + return RT_EOK; +} + +static rt_err_t spacemit_pm_add_subdomain(struct spacemit_pmu *pmu, + struct rt_ofw_node *parent) +{ + rt_err_t err = RT_EOK; + rt_uint32_t idx; + struct rt_ofw_node *np; + struct spacemit_pm_domain *child_spd, *parent_spd; + + rt_ofw_foreach_child_node(parent, np) + { + if ((err = rt_ofw_prop_read_u32(np, "reg", &idx))) + { + LOG_E("Failed to read %s domain id (reg) error = %s", + rt_ofw_node_full_name(parent), rt_strerror(err)); + goto _err; + } + + parent_spd = &pmu->domains[idx]; + + if ((err = spacemit_pm_add_one_domain(pmu, np))) + { + LOG_E("Failed to handle node %s error = %s", + rt_ofw_node_full_name(np), rt_strerror(err)); + goto _err; + } + + if ((err = rt_ofw_prop_read_u32(np, "reg", &idx))) + { + LOG_E("Failed to read %s domain id (reg) error = %s", + rt_ofw_node_full_name(np), rt_strerror(err)); + goto _err; + } + + child_spd = &pmu->domains[idx]; + + if ((err = rt_dm_power_domain_register_child(&parent_spd->parent, + &child_spd->parent))) + { + LOG_E("Failed to handle subdomain node %s error = %s", + rt_ofw_node_full_name(np), rt_strerror(err)); + } + + spacemit_pm_add_subdomain(pmu, np); + } + +_err: + rt_ofw_node_put(np); + + return err; +} + +static rt_err_t spacemit_pmdomain_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct rt_ofw_node *np = dev->ofw_node, *child; + struct spacemit_pmu *pmu = rt_calloc(1, sizeof(*pmu)); + + if (!pmu) + { + return -RT_ENOMEM; + } + + pmu->mpmu_regmap = rt_syscon_find_by_ofw_compatible("spacemit,spacemit-mpmu"); + pmu->apmu_regmap = rt_syscon_find_by_ofw_compatible("spacemit,spacemit-apmu"); + + if (!pmu->mpmu_regmap || !pmu->apmu_regmap) + { + err = -RT_EINVAL; + goto _fail; + } + + if (rt_dm_dev_prop_read_u32(dev, "domains", &pmu->num_domains)) + { + err = -RT_EINVAL; + goto _fail; + } + + if (!(pmu->domains = rt_calloc(pmu->num_domains, sizeof(*pmu->domains)))) + { + err = -RT_EINVAL; + goto _fail; + } + + rt_ofw_foreach_available_child_node(np, child) + { + if ((err = spacemit_pm_add_one_domain(pmu, child))) + { + LOG_E("Failed to handle node %s error = %s", + rt_ofw_node_full_name(child), rt_strerror(err)); + + rt_ofw_node_put(child); + goto _fail; + } + + if ((err = spacemit_pm_add_subdomain(pmu, child))) + { + LOG_E("Failed to handle subdomain node %s error = %s", + rt_ofw_node_full_name(child), rt_strerror(err)); + + rt_ofw_node_put(child); + goto _fail; + } + } + + pmu->parent.ofw_parse = spacemit_pmdomain_proxy_ofw_parse; + rt_dm_power_domain_proxy_ofw_bind(&pmu->parent, np); + + return RT_EOK; + +_fail: + if (pmu->domains) + { + for (int i = 0; i < pmu->num_domains; ++i) + { + struct spacemit_pm_domain *domain = &pmu->domains[i]; + + if (domain) + { + rt_dm_power_domain_unregister(&domain->parent); + } + } + + rt_free(pmu->domains); + } + rt_free(pmu); + + return err; +} + +static const struct rt_ofw_node_id spacemit_pmdomain_ofw_ids[] = +{ + { .compatible = "spacemit,power-controller", }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_pmdomain_driver = +{ + .name = "spacemit-pmdomain", + .ids = spacemit_pmdomain_ofw_ids, + + .probe = spacemit_pmdomain_probe, +}; + +static int spacemit_pmdomain_drv_register(void) +{ + rt_platform_driver_register(&spacemit_pmdomain_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(spacemit_pmdomain_drv_register); diff --git a/bsp/spacemit/dm/power/SConscript b/bsp/spacemit/dm/power/SConscript new file mode 100644 index 000000000000..0b84689e91c6 --- /dev/null +++ b/bsp/spacemit/dm/power/SConscript @@ -0,0 +1,11 @@ +from building import * + +cwd = GetCurrentDir() +objs = [] +list = os.listdir(cwd) + +for d in list: + path = os.path.join(cwd, d) + if os.path.isfile(os.path.join(path, 'SConscript')): + objs = objs + SConscript(os.path.join(d, 'SConscript')) +Return('objs') diff --git a/bsp/spacemit/dm/power/reset/Kconfig b/bsp/spacemit/dm/power/reset/Kconfig new file mode 100644 index 000000000000..d6d5e69849f4 --- /dev/null +++ b/bsp/spacemit/dm/power/reset/Kconfig @@ -0,0 +1,2 @@ +config RT_POWER_RESET_REBOOT_SPACEMIT + bool "Spacemit reboot" diff --git a/bsp/spacemit/dm/power/reset/SConscript b/bsp/spacemit/dm/power/reset/SConscript new file mode 100644 index 000000000000..943fda9cbafc --- /dev/null +++ b/bsp/spacemit/dm/power/reset/SConscript @@ -0,0 +1,12 @@ +from building import * + +cwd = GetCurrentDir() +src = [] +CPPPATH = [cwd + '/../../include'] + +if GetDepend(['RT_POWER_RESET_REBOOT_SPACEMIT']): + src += ['reboot-spacemit.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/power/reset/reboot-spacemit.c b/bsp/spacemit/dm/power/reset/reboot-spacemit.c new file mode 100644 index 000000000000..3fe266be0650 --- /dev/null +++ b/bsp/spacemit/dm/power/reset/reboot-spacemit.c @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include + +#define DBG_TAG "reset.reboot.spacemit" +#define DBG_LVL DBG_INFO +#include + +struct spacemit_reboot +{ + void *regs; +}; + +static rt_err_t spacemit_notify_reboot(struct rt_device *dev, char *cmd) +{ + struct spacemit_reboot *reboot = dev->user_data; + + if (cmd) + { + if (!rt_strcmp(cmd, "fastboot")) + { + HWREG32(reboot->regs) = 0x55a; + } + else if (!rt_strcmp(cmd, "uboot")) + { + HWREG32(reboot->regs) = 0x55f; + } + } + + return RT_EOK; +} + +static rt_err_t spacemit_reboot_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct spacemit_reboot *reboot = rt_calloc(1, sizeof(*reboot)); + + if (!reboot) + { + return -RT_ENOMEM; + } + + if (!(reboot->regs = rt_dm_dev_iomap(dev, 0))) + { + err = -RT_ENOMEM; + goto _fail; + } + + if ((err = rt_dm_reboot_mode_register(dev, spacemit_notify_reboot))) + { + goto _fail; + } + + dev->user_data = reboot; + + return RT_EOK; + +_fail: + if (reboot->regs) + { + rt_iounmap(reboot->regs); + } + + rt_free(reboot); + + return err; +} + +static rt_err_t spacemit_reboot_remove(struct rt_platform_device *pdev) +{ + struct spacemit_reboot *reboot = pdev->parent.user_data; + + rt_dm_reboot_mode_unregister(&pdev->parent); + + rt_iounmap(reboot->regs); + + rt_free(reboot); + + return RT_EOK; +} + +static const struct rt_ofw_node_id spacemit_reboot_ofw_ids[] = +{ + { .compatible = "spacemit,k1x-reboot", }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_reboot_driver = +{ + .name = "spacemit-reboot", + .ids = spacemit_reboot_ofw_ids, + + .probe = spacemit_reboot_probe, + .remove = spacemit_reboot_remove, +}; + +static int spacemit_reboot_drv_register(void) +{ + rt_platform_driver_register(&spacemit_reboot_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(spacemit_reboot_drv_register); diff --git a/bsp/spacemit/dm/pwm/Kconfig b/bsp/spacemit/dm/pwm/Kconfig new file mode 100644 index 000000000000..152c82d8a29d --- /dev/null +++ b/bsp/spacemit/dm/pwm/Kconfig @@ -0,0 +1,4 @@ +config RT_PWM_PXA + bool "PXA PWM support" + depends on RT_USING_PWM + default n diff --git a/bsp/spacemit/dm/pwm/SConscript b/bsp/spacemit/dm/pwm/SConscript new file mode 100644 index 000000000000..e9e880eae3e2 --- /dev/null +++ b/bsp/spacemit/dm/pwm/SConscript @@ -0,0 +1,14 @@ +from building import * + +group = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +src = [] + +if GetDepend(['RT_PWM_PXA']): + src += ['pwm-pxa.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/pwm/pwm-pxa.c b/bsp/spacemit/dm/pwm/pwm-pxa.c new file mode 100644 index 000000000000..7131de805318 --- /dev/null +++ b/bsp/spacemit/dm/pwm/pwm-pxa.c @@ -0,0 +1,331 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include + +#define DBG_TAG "pwm.pxa" +#define DBG_LVL DBG_INFO +#include + +#define PWMCR 0x00 +#define PWMDCR 0x04 +#define PWMPCR 0x08 + +#define PWMCR_SD RT_BIT(6) +#define PWMDCR_FD RT_BIT(10) + +struct pxa_pwm +{ + struct rt_device_pwm parent; + + void *regs; + struct rt_clk *clk; + struct rt_reset_control *rstc; + + int dcr_fd; /* Controller PWM_DCR FD feature */ + int rcpu_pwm; /* PWM in rcpu domain */ + rt_bool_t enabled; + +#define QUIRK_HAS_SECONDARY_PWM 0 +#define QUIRK_HAS_PWM_DCR_FD 1 + rt_bitmap_t quirks; +}; + +#define raw_to_pxa_pwm(raw) rt_container_of(raw, struct pxa_pwm, parent) + +static rt_err_t pxa_pwm_toggle(struct pxa_pwm *pc, rt_bool_t enabled) +{ + rt_err_t err = RT_EOK; + + if (pc->enabled == enabled) + { + return err; + } + + if (pc->enabled) + { + rt_clk_disable_unprepare(pc->clk); + } + else + { + err = rt_clk_prepare_enable(pc->clk); + } + + pc->enabled = enabled; + + return err; +} + +static rt_err_t pxa_pwm_apply(struct pxa_pwm *pc, struct rt_pwm_configuration *pwm_cfg) +{ + rt_err_t err; + rt_bool_t enabled; + rt_uint32_t offset; + rt_uint64_t clk, duty_ns, period_ns; + rt_ubase_t period_cycles, prescale, pv, dc; + + if (pwm_cfg->complementary) + { + return -RT_EINVAL; + } + + enabled = pc->enabled; + + if ((err = pxa_pwm_toggle(pc, RT_FALSE))) + { + return err; + } + + /* + * period_ns = 10^9 * (PRESCALE + 1) * (PV + 1) / PWM_CLK_RATE + * duty_ns = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE + */ + duty_ns = enabled ? pwm_cfg->pulse : 0; + period_ns = pwm_cfg->period; + offset = pwm_cfg->channel ? 0x10 : 0; + + clk = rt_clk_get_rate(pc->clk); + clk *= period_ns; + rt_do_div(clk, 1000000000); + period_cycles = clk; + + if (period_cycles < 1) + { + period_cycles = 1; + } + prescale = (period_cycles - 1) / 1024; + pv = period_cycles / (prescale + 1) - 1; + + if (prescale > 63) + { + err = -RT_EINVAL; + goto _end; + } + + if (duty_ns == period_ns) + { + if (pc->quirks & RT_BIT(QUIRK_HAS_PWM_DCR_FD)) + { + if (pc->dcr_fd) + { + dc = PWMDCR_FD; + } + else + { + dc = (pv + 1) * duty_ns / period_ns; + + if (dc >= PWMDCR_FD) + { + dc = PWMDCR_FD - 1; + pv = dc - 1; + } + } + } + else + { + dc = PWMDCR_FD; + } + } + else + { + dc = ((rt_uint64_t)(pv + 1) * duty_ns) / period_ns; + } + + if (pc->quirks & RT_BIT(QUIRK_HAS_PWM_DCR_FD)) + { + prescale |= PWMCR_SD; + } + + HWREG32(pc->regs + offset + PWMCR) = prescale | PWMCR_SD; + HWREG32(pc->regs + offset + PWMDCR) = dc; + HWREG32(pc->regs + offset + PWMPCR) = pv; + +_end: + if (pc->enabled != enabled) + { + err = pxa_pwm_toggle(pc, RT_TRUE); + } + + return err; +} + +static rt_err_t pxa_pwm_control(struct rt_device_pwm *pwm, int cmd, void *args) +{ + rt_err_t err; + struct pxa_pwm *pc = raw_to_pxa_pwm(pwm); + struct rt_pwm_configuration *pwm_cfg = args; + + if (pwm_cfg->channel > 0) + { + if (pwm_cfg->channel > 1 || !pc->quirks & RT_BIT(QUIRK_HAS_SECONDARY_PWM)) + { + return -RT_EINVAL; + } + } + + /* RT_PWM framework have check args */ + switch (cmd) + { + case PWM_CMD_ENABLE: + case PWM_CMD_DISABLE: + err = pxa_pwm_toggle(pc, cmd == PWM_CMD_ENABLE); + break; + + case PWM_CMD_SET: + case PWM_CMD_SET_PERIOD: + case PWM_CMD_SET_PULSE: + err = pxa_pwm_apply(pc, pwm_cfg); + break; + + case PWM_CMD_GET: + err = -RT_ENOSYS; + break; + + default: + err = -RT_EINVAL; + break; + } + + return err; +} + +const static struct rt_pwm_ops pxa_pwm_ops = +{ + .control = pxa_pwm_control, +}; + +static void pxa_pwm_free(struct pxa_pwm *pc) +{ + if (pc->regs) + { + rt_iounmap(pc->regs); + } + + if (rt_is_err_or_null(pc->clk)) + { + rt_clk_put(pc->clk); + } + + if (rt_is_err_or_null(pc->rstc)) + { + rt_reset_control_assert(pc->rstc); + rt_reset_control_put(pc->rstc); + } + + rt_free(pc); +} + +static rt_err_t pxa_pwm_probe(struct rt_platform_device *pdev) +{ + int id; + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct pxa_pwm *pc = rt_calloc(1, sizeof(*pc)); + + if (!pc) + { + return -RT_ENOMEM; + } + + pc->quirks = pdev->id->data ? *(rt_ubase_t *)pdev->id->data : 0; + + if (pc->quirks & RT_BIT(QUIRK_HAS_PWM_DCR_FD)) + { + pc->dcr_fd = rt_dm_dev_prop_read_bool(dev, "k1x,pwm-disable-fd") ? 0 : 1; + pc->rcpu_pwm = rt_dm_dev_prop_read_bool(dev, "rcpu-pwm") ? 1 : 0; + } + + pc->regs = rt_dm_dev_iomap(dev, 0); + if (!pc->regs) + { + err = -RT_EIO; + goto _fail; + } + + pc->clk = rt_clk_get_by_index(dev, 0); + if (rt_is_err(pc->clk)) + { + err = rt_ptr_err(pc->clk); + goto _fail; + } + + pc->rstc = rt_reset_control_get_by_index(dev, 0); + if (rt_is_err(pc->rstc)) + { + err = rt_ptr_err(pc->rstc); + goto _fail; + } + rt_reset_control_deassert(pc->rstc); + + dev->user_data = pc; + + pc->parent.parent.ofw_node = dev->ofw_node; + + if ((id = pdev->dev_id) >= 0) + { + rt_dm_dev_set_name(&pc->parent.parent, "pwm%u", id); + } + else + { + rt_dm_dev_set_name_auto(&pc->parent.parent, "pwm"); + } + + rt_device_pwm_register(&pc->parent, + rt_dm_dev_get_name(&pc->parent.parent), &pxa_pwm_ops, pc); + + rt_dm_dev_bind_fwdata(dev, RT_NULL, pc); + + return RT_EOK; + +_fail: + pxa_pwm_free(pc); + + return err; +} + +static rt_err_t pxa_pwm_remove(struct rt_platform_device *pdev) +{ + struct rt_device *dev = &pdev->parent; + struct pxa_pwm *pc = dev->user_data; + + pxa_pwm_toggle(pc, RT_FALSE); + + rt_dm_dev_unbind_fwdata(dev, RT_NULL); + + rt_device_unregister(&pc->parent.parent); + + pxa_pwm_free(pc); + + return RT_EOK; +} + +static rt_bitmap_t has_secondary_pwm_quirk = RT_BIT(QUIRK_HAS_SECONDARY_PWM); +static rt_bitmap_t has_pwm_dcr_fd_quirk = RT_BIT(QUIRK_HAS_PWM_DCR_FD); + +static const struct rt_ofw_node_id pxa_pwm_ofw_ids[] = +{ + { .compatible = "marvell,pxa250-pwm", }, + { .compatible = "marvell,pxa270-pwm", .data = &has_secondary_pwm_quirk }, + { .compatible = "marvell,pxa168-pwm", }, + { .compatible = "marvell,pxa910-pwm", }, + { .compatible = "spacemit,k1x-pwm", .data = &has_pwm_dcr_fd_quirk }, + { /* sentinel */ } +}; + +static struct rt_platform_driver pxa_pwm_driver = +{ + .name = "pxa-pwm", + .ids = pxa_pwm_ofw_ids, + + .probe = pxa_pwm_probe, + .remove = pxa_pwm_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(pxa_pwm_driver); diff --git a/bsp/spacemit/dm/regulator/Kconfig b/bsp/spacemit/dm/regulator/Kconfig new file mode 100644 index 000000000000..ad93c9818649 --- /dev/null +++ b/bsp/spacemit/dm/regulator/Kconfig @@ -0,0 +1,5 @@ +config RT_REGULATOR_SPACEMIT_PMIC + bool "Spacemit PMIC Power regulators" + depends on RT_MFD_SPACEMIT_PMIC + depends on RT_USING_PIN + default y diff --git a/bsp/spacemit/dm/regulator/SConscript b/bsp/spacemit/dm/regulator/SConscript new file mode 100644 index 000000000000..48bce18d883a --- /dev/null +++ b/bsp/spacemit/dm/regulator/SConscript @@ -0,0 +1,12 @@ +from building import * + +cwd = GetCurrentDir() +src = [] +CPPPATH = [cwd + '/../include', cwd + '/../../../../components/drivers/regulator'] + +if GetDepend(['RT_REGULATOR_SPACEMIT_PMIC']): + src += ['regulator-spacemit-pmic.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/regulator/regulator-spacemit-pmic.c b/bsp/spacemit/dm/regulator/regulator-spacemit-pmic.c new file mode 100644 index 000000000000..731c083da10c --- /dev/null +++ b/bsp/spacemit/dm/regulator/regulator-spacemit-pmic.c @@ -0,0 +1,413 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#define DBG_TAG "regulator.spacemit-pmic" +#define DBG_LVL DBG_INFO +#include + +#include "regulator_dm.h" + +#define __SPACEMIT_REGULATOR_INTERNAL +static const struct rt_regulator_ops pmic_dcdc_ldo_ops, pmic_switch_ops; + +#include + +struct spacemit_pmic_regulator +{ + struct rt_regulator_node parent; + struct rt_regulator_param param; + + struct rt_device device; + struct spacemit_pmic *pmic; + struct rt_ofw_node *ofw_node; + + const struct spacemit_pmic_regulator_desc *desc; +}; + +#define raw_to_spacemit_pmic_regulator(raw) rt_container_of(raw, struct spacemit_pmic_regulator, parent) + +static int regulator_voltage_from_selector(struct spacemit_pmic_regulator *pmic_reg, + int selector) +{ + int uvolt = -1; + const struct spacemit_pmic_regulator_desc *desc = pmic_reg->desc; + + if (desc->ranges_nr) + { + const struct spacemit_pmic_regulator_range *range = &desc->ranges[0]; + + for (int i = desc->ranges_nr - 1; i >= 0; --i, ++range) + { + if (range->min_sel <= selector && range->max_sel >= selector) + { + if (range->min_sel > selector || range->max_sel < selector) + { + return -RT_EINVAL; + } + + uvolt = range->min + (selector - range->min_sel) * range->step; + + break; + } + } + } + else if (desc->voltages_nr) + { + if (selector >= desc->voltages_nr) + { + return -RT_EINVAL; + } + + return desc->uvolt_min + (desc->uvolt_step * selector); + } + else + { + LOG_E("Regulator %s-%s voltages info not found", desc->name, desc->supply_name); + } + + return uvolt; +} + +static int regulator_voltage_to_selector_range(struct spacemit_pmic_regulator *pmic_reg, + int min_uvolt, int max_uvolt) +{ + int selector = 0, max, uvolt, i; + const struct spacemit_pmic_regulator_range *range; + const struct spacemit_pmic_regulator_desc *desc = pmic_reg->desc; + + if (!desc->ranges) + { + return -RT_EINVAL; + } + + for (i = 0; i < desc->ranges_nr; ++i) + { + range = &desc->ranges[i]; + max = range->min + (range->max_sel - range->min_sel) * range->step; + + if (max < min_uvolt) + { + continue; + } + + if (range->min > min_uvolt) + { + selector = range->min_sel; + } + else if (range->step == 0) + { + selector = range->max_sel; + } + else + { + selector = RT_DIV_ROUND_UP(min_uvolt - range->min, range->step) + + range->min_sel; + } + + uvolt = regulator_voltage_from_selector(pmic_reg, selector); + + if (uvolt >= min_uvolt && uvolt <= max_uvolt) + { + break; + } + } + + if (i == desc->ranges_nr) + { + return -RT_EINVAL; + } + + return selector; +} + +static int regulator_voltage_to_selector(struct spacemit_pmic_regulator *pmic_reg, + int min_uvolt, int max_uvolt) +{ + int selector, uvolt; + + /* Allow uvolt_step to be 0 for fixed voltage */ + if (pmic_reg->desc->voltages_nr == 1 && pmic_reg->desc->uvolt_step == 0) + { + if (min_uvolt <= pmic_reg->desc->uvolt_min && pmic_reg->desc->uvolt_min <= max_uvolt) + { + return 0; + } + else + { + return -RT_EINVAL; + } + } + + if (!pmic_reg->desc->uvolt_step) + { + return -RT_EINVAL; + } + + if (min_uvolt < pmic_reg->desc->uvolt_min) + { + min_uvolt = pmic_reg->desc->uvolt_min; + } + + selector = RT_DIV_ROUND_UP(min_uvolt - pmic_reg->desc->uvolt_min, pmic_reg->desc->uvolt_step); + + if (selector < 0) + { + return selector; + } + + /* Map back into a voltage to verify we're still in bounds */ + uvolt = regulator_voltage_from_selector(pmic_reg, selector); + + if (uvolt < min_uvolt || uvolt > max_uvolt) + { + return -RT_EINVAL; + } + + return selector; +} + +static rt_err_t spacemit_pmic_regulator_enable(struct rt_regulator_node *reg_np) +{ + rt_uint32_t val; + struct spacemit_pmic_regulator *pmic_reg = raw_to_spacemit_pmic_regulator(reg_np); + + val = pmic_reg->desc->enable_val; + + if (!val) + { + val = pmic_reg->desc->enable_mask; + } + + return spacemit_pmic_update_bits(pmic_reg->pmic, pmic_reg->desc->enable_reg, + pmic_reg->desc->enable_mask, val); +} + +static rt_err_t spacemit_pmic_regulator_disable(struct rt_regulator_node *reg_np) +{ + rt_uint32_t val; + struct spacemit_pmic_regulator *pmic_reg = raw_to_spacemit_pmic_regulator(reg_np); + + val = pmic_reg->desc->disable_val; + + return spacemit_pmic_update_bits(pmic_reg->pmic, pmic_reg->desc->enable_reg, + pmic_reg->desc->enable_mask, val); +} + +static rt_bool_t spacemit_pmic_regulator_is_enabled(struct rt_regulator_node *reg_np) +{ + rt_uint32_t val; + struct spacemit_pmic_regulator *pmic_reg = raw_to_spacemit_pmic_regulator(reg_np); + + val = spacemit_pmic_read(pmic_reg->pmic, pmic_reg->desc->enable_reg); + + if ((rt_err_t)val < 0) + { + return RT_FALSE; + } + + val &= pmic_reg->desc->enable_mask; + + if (pmic_reg->desc->enable_val) + { + return val == pmic_reg->desc->enable_val; + } + + return val != 0; +} + +static rt_err_t spacemit_pmic_regulator_set_voltage(struct rt_regulator_node *reg_np, + int min_uvolt, int max_uvolt) +{ + int selector; + struct spacemit_pmic_regulator *pmic_reg = raw_to_spacemit_pmic_regulator(reg_np); + + selector = regulator_voltage_to_selector(pmic_reg, min_uvolt, max_uvolt); + + if (selector < 0) + { + if (selector == -RT_EINVAL) + { + selector = regulator_voltage_to_selector_range(pmic_reg, + min_uvolt, max_uvolt); + + if (selector < 0) + { + return -RT_EINVAL; + } + } + } + + selector <<= __rt_ffs(pmic_reg->desc->vsel_mask) - 1; + + return spacemit_pmic_update_bits(pmic_reg->pmic, pmic_reg->desc->vsel_reg, + pmic_reg->desc->vsel_mask, selector); +} + +static int spacemit_pmic_regulator_get_voltage(struct rt_regulator_node *reg_np) +{ + int uvolt; + rt_uint32_t val; + struct spacemit_pmic_regulator *pmic_reg = raw_to_spacemit_pmic_regulator(reg_np); + + val = spacemit_pmic_read(pmic_reg->pmic, pmic_reg->desc->vsel_reg); + + if ((rt_err_t)val < 0) + { + return val; + } + + val &= pmic_reg->desc->vsel_mask; + val >>= __rt_ffs(pmic_reg->desc->vsel_mask) - 1; + + uvolt = regulator_voltage_from_selector(pmic_reg, val); + + return uvolt < 0 ? -RT_EINVAL : uvolt; +} + +static const struct rt_regulator_ops pmic_dcdc_ldo_ops = +{ + .enable = spacemit_pmic_regulator_enable, + .disable = spacemit_pmic_regulator_disable, + .is_enabled = spacemit_pmic_regulator_is_enabled, + .set_voltage = spacemit_pmic_regulator_set_voltage, + .get_voltage = spacemit_pmic_regulator_get_voltage, +}; + +static const struct rt_regulator_ops pmic_switch_ops = +{ + .enable = spacemit_pmic_regulator_enable, + .disable = spacemit_pmic_regulator_disable, + .is_enabled = spacemit_pmic_regulator_is_enabled, +}; + +static rt_err_t append_spacemit_pmic_regulator(struct spacemit_pmic *pmic, + struct rt_ofw_node *np, const struct spacemit_pmic_regulator_desc *desc, int id) +{ + rt_err_t err = RT_EOK; + struct rt_regulator_node *rgp; + struct spacemit_pmic_regulator *pmic_reg; + + pmic_reg = rt_calloc(1, sizeof(*pmic_reg)); + + if (!pmic_reg) + { + return -RT_ENOMEM; + } + + pmic_reg->pmic = pmic; + pmic_reg->desc = &desc[id]; + + regulator_ofw_parse(np, &pmic_reg->param); + + rgp = &pmic_reg->parent; + rgp->supply_name = pmic_reg->param.name; + rgp->ops = pmic_reg->desc->ops; + rgp->param = &pmic_reg->param; + rgp->dev = &pmic_reg->device; + + rgp->dev->ofw_node = np; + + if ((err = rt_regulator_register(rgp))) + { + goto _fail; + } + + return RT_EOK; + +_fail: + rt_free(pmic_reg); + + return err; +} + +static rt_err_t spacemit_pmic_regulator_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_ofw_node *np, *regulators_np = pdev->parent.ofw_node; + struct spacemit_pmic *pmic = pdev->priv, *pmic_sub; + const struct spacemit_pmic_regulator_data *data = pdev->id->data; + struct spacemit_pmic_regulator *pmic_reg = rt_calloc(1, sizeof(*pmic_reg)); + + if (!pmic_reg) + { + return -RT_ENOMEM; + } + + if (rt_ofw_node_is_compatible(regulators_np, "pmic,regulator,pm853")) + { + if (!(pmic_sub = rt_calloc(1, sizeof(*pmic_sub)))) + { + err = -RT_ENOMEM; + goto _fail; + } + + rt_memcpy(pmic_sub, pmic, sizeof(*pmic)); + pmic_sub->addr_offset = 1; + + pmic_reg->pmic = pmic_sub; + } + else + { + pmic_reg->pmic = pmic; + } + + for (int i = 0; i < data->desc_nr; ++i) + { + const char *name = data->desc[i].name; + + if (!(np = rt_ofw_get_child_by_tag(regulators_np, name))) + { + continue; + } + + rt_ofw_node_put(np); + + if ((err = append_spacemit_pmic_regulator(pmic, np, data->desc, i))) + { + LOG_E("Append spacemit PMIC regulator %s fail error = %s", + rt_ofw_node_full_name(np), rt_strerror(err)); + + if (err == -RT_ENOMEM) + { + return err; + } + } + } + + return RT_EOK; +_fail: + rt_free(pmic_reg); + + return err; +} + +static const struct rt_ofw_node_id spacemit_pmic_regulator_ofw_ids[] = +{ + { .compatible = "pmic,regulator,spm8821", .data = &spm8821_regulator_data }, + { .compatible = "pmic,regulator,pm853", .data = &pm853_regulator_data }, + { .compatible = "pmic,regulator,sy8810l", .data = &sy8810l_regulator_data }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_pmic_regulator_driver = +{ + .name = "spacemit-pmic-regulator", + .ids = spacemit_pmic_regulator_ofw_ids, + + .probe = spacemit_pmic_regulator_probe, +}; + +static int spacemit_pmic_regulator_register(void) +{ + rt_platform_driver_register(&spacemit_pmic_regulator_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(spacemit_pmic_regulator_register); diff --git a/bsp/spacemit/dm/reset/Kconfig b/bsp/spacemit/dm/reset/Kconfig new file mode 100644 index 000000000000..b0b81e00898a --- /dev/null +++ b/bsp/spacemit/dm/reset/Kconfig @@ -0,0 +1,4 @@ +config RT_RESET_SPACEMIT_K1 + bool "Reset controller driver for Spacemit K1" + depends on RT_USING_RESET + default y diff --git a/bsp/spacemit/dm/reset/SConscript b/bsp/spacemit/dm/reset/SConscript new file mode 100644 index 000000000000..3994acfe37b3 --- /dev/null +++ b/bsp/spacemit/dm/reset/SConscript @@ -0,0 +1,13 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_RESET_SPACEMIT_K1']): + src += ['reset-spacemit-k1x.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/reset/reset-spacemit-k1x.c b/bsp/spacemit/dm/reset/reset-spacemit-k1x.c new file mode 100644 index 000000000000..567828e18e1b --- /dev/null +++ b/bsp/spacemit/dm/reset/reset-spacemit-k1x.c @@ -0,0 +1,332 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include + +#define DBG_TAG "reset.spacemit.k1x" +#define DBG_LVL DBG_INFO +#include + +#include +#include + +struct spacemit_reset_signal +{ + rt_uint32_t offset; + rt_uint32_t mask; + rt_uint32_t deassert_val; + rt_uint32_t assert_val; + enum cru_type type; +}; + +struct spacemit_reset +{ + struct rt_reset_controller parent; + + union + { + struct + { + void *mpmu_base; + void *apmu_base; + void *apbc_base; + void *apbs_base; + void *ciu_base; + void *dciu_base; + void *ddrc_base; + void *apbc2_base; + void *rcpu_base; + void *rcpu2_base; + void *audpmu_base; + void *audio_ctrl_base; + }; + void *mmio[CRU_BASE_TYPE_MAX]; + }; + + rt_uint32_t signals_nr; + const struct spacemit_reset_signal *signals; +}; + +#define RESET_SIGNAL(name, offset, mask, deassert_val, assert_val, type) \ +[RESET_##name] = \ +{ \ + offset, mask, deassert_val, assert_val, CRU_BASE_TYPE_##type, \ +} \ + +static const struct spacemit_reset_signal k1x_reset_signals[RESET_NUMBER] = +{ + RESET_SIGNAL(UART1, APBC_UART1_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(UART2, APBC_UART2_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(GPIO, APBC_GPIO_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(PWM0, APBC_PWM0_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), APBC), + RESET_SIGNAL(PWM1, APBC_PWM1_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), APBC), + RESET_SIGNAL(PWM2, APBC_PWM2_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), APBC), + RESET_SIGNAL(PWM3, APBC_PWM3_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), APBC), + RESET_SIGNAL(PWM4, APBC_PWM4_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), APBC), + RESET_SIGNAL(PWM5, APBC_PWM5_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), APBC), + RESET_SIGNAL(PWM6, APBC_PWM6_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), APBC), + RESET_SIGNAL(PWM7, APBC_PWM7_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), APBC), + RESET_SIGNAL(PWM8, APBC_PWM8_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), APBC), + RESET_SIGNAL(PWM9, APBC_PWM9_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), APBC), + RESET_SIGNAL(PWM10, APBC_PWM10_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), APBC), + RESET_SIGNAL(PWM11, APBC_PWM11_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), APBC), + RESET_SIGNAL(PWM12, APBC_PWM12_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), APBC), + RESET_SIGNAL(PWM13, APBC_PWM13_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), APBC), + RESET_SIGNAL(PWM14, APBC_PWM14_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), APBC), + RESET_SIGNAL(PWM15, APBC_PWM15_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), APBC), + RESET_SIGNAL(PWM16, APBC_PWM16_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), APBC), + RESET_SIGNAL(PWM17, APBC_PWM17_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), APBC), + RESET_SIGNAL(PWM18, APBC_PWM18_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), APBC), + RESET_SIGNAL(PWM19, APBC_PWM19_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), APBC), + RESET_SIGNAL(SSP3, APBC_SSP3_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(UART3, APBC_UART3_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(RTC, APBC_RTC_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(TWSI0, APBC_TWSI0_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(TIMERS1, APBC_TIMERS1_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(AIB, APBC_AIB_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(TIMERS2, APBC_TIMERS2_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(ONEWIRE, APBC_ONEWIRE_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(SSPA0, APBC_SSPA0_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(SSPA1, APBC_SSPA1_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(DRO, APBC_DRO_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(IR, APBC_IR_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(TWSI1, APBC_TWSI1_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(TSEN, APBC_TSEN_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(TWSI2, APBC_TWSI2_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(TWSI4, APBC_TWSI4_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(TWSI5, APBC_TWSI5_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(TWSI6, APBC_TWSI6_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(TWSI7, APBC_TWSI7_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(TWSI8, APBC_TWSI8_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(IPC_AP2AUD, APBC_IPC_AP2AUD_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(UART4, APBC_UART4_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(UART5, APBC_UART5_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(UART6, APBC_UART6_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(UART7, APBC_UART7_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(UART8, APBC_UART8_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(UART9, APBC_UART9_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + RESET_SIGNAL(CAN0, APBC_CAN0_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC), + /* MPMU */ + RESET_SIGNAL(WDT, MPMU_WDTPCR, RT_BIT(2), 0, RT_BIT(2), MPMU), + /* APMU */ + RESET_SIGNAL(JPG, APMU_JPG_CLK_RES_CTRL, RT_BIT(0), RT_BIT(0), 0, APMU), + RESET_SIGNAL(CSI, APMU_CSI_CCIC2_CLK_RES_CTRL, RT_BIT(1), RT_BIT(1), 0, APMU), + RESET_SIGNAL(CCIC2_PHY, APMU_CSI_CCIC2_CLK_RES_CTRL, RT_BIT(2), RT_BIT(2), 0, APMU), + RESET_SIGNAL(CCIC3_PHY, APMU_CSI_CCIC2_CLK_RES_CTRL, RT_BIT(29), RT_BIT(29), 0, APMU), + RESET_SIGNAL(ISP, APMU_ISP_CLK_RES_CTRL, RT_BIT(0), RT_BIT(0), 0, APMU), + RESET_SIGNAL(ISP_AHB, APMU_ISP_CLK_RES_CTRL, RT_BIT(3), RT_BIT(3), 0, APMU), + RESET_SIGNAL(ISP_CI, APMU_ISP_CLK_RES_CTRL, RT_BIT(16), RT_BIT(16), 0, APMU), + RESET_SIGNAL(ISP_CPP, APMU_ISP_CLK_RES_CTRL, RT_BIT(27), RT_BIT(27), 0, APMU), + RESET_SIGNAL(LCD, APMU_LCD_CLK_RES_CTRL1, RT_BIT(4), RT_BIT(4), 0, APMU), + RESET_SIGNAL(DSI_ESC, APMU_LCD_CLK_RES_CTRL1, RT_BIT(3), RT_BIT(3), 0, APMU), + RESET_SIGNAL(V2D, APMU_LCD_CLK_RES_CTRL1, RT_BIT(27), RT_BIT(27), 0, APMU), + RESET_SIGNAL(MIPI, APMU_LCD_CLK_RES_CTRL1, RT_BIT(15), RT_BIT(15), 0, APMU), + RESET_SIGNAL(LCD_SPI, APMU_LCD_SPI_CLK_RES_CTRL, RT_BIT(0), RT_BIT(0), 0, APMU), + RESET_SIGNAL(LCD_SPI_BUS, APMU_LCD_SPI_CLK_RES_CTRL, RT_BIT(4), RT_BIT(4), 0, APMU), + RESET_SIGNAL(LCD_SPI_HBUS, APMU_LCD_SPI_CLK_RES_CTRL, RT_BIT(2), RT_BIT(2), 0, APMU), + RESET_SIGNAL(LCD_MCLK, APMU_LCD_CLK_RES_CTRL2, RT_BIT(9), RT_BIT(9), 0, APMU), + RESET_SIGNAL(CCIC_4X, APMU_CCIC_CLK_RES_CTRL, RT_BIT(1), RT_BIT(1), 0, APMU), + RESET_SIGNAL(CCIC1_PHY, APMU_CCIC_CLK_RES_CTRL, RT_BIT(2), RT_BIT(2), 0, APMU), + RESET_SIGNAL(SDH_AXI, APMU_SDH0_CLK_RES_CTRL, RT_BIT(0), RT_BIT(0), 0, APMU), + RESET_SIGNAL(SDH0, APMU_SDH0_CLK_RES_CTRL, RT_BIT(1), RT_BIT(1), 0, APMU), + RESET_SIGNAL(SDH1, APMU_SDH1_CLK_RES_CTRL, RT_BIT(1), RT_BIT(1), 0, APMU), + RESET_SIGNAL(USB_AXI, APMU_USB_CLK_RES_CTRL, RT_BIT(0), RT_BIT(0), 0, APMU), + RESET_SIGNAL(USBP1_AXI, APMU_USB_CLK_RES_CTRL, RT_BIT(4), RT_BIT(4), 0, APMU), + RESET_SIGNAL(USB3_0, APMU_USB_CLK_RES_CTRL, RT_BIT(9) | RT_BIT(10) | RT_BIT(11), RT_BIT(9) | RT_BIT(10) | RT_BIT(11), 0, APMU), + RESET_SIGNAL(QSPI, APMU_QSPI_CLK_RES_CTRL, RT_BIT(1), RT_BIT(1), 0, APMU), + RESET_SIGNAL(QSPI_BUS, APMU_QSPI_CLK_RES_CTRL, RT_BIT(0), RT_BIT(0), 0, APMU), + RESET_SIGNAL(DMA, APMU_DMA_CLK_RES_CTRL, RT_BIT(0), RT_BIT(0), 0, APMU), + RESET_SIGNAL(AES, APMU_AES_CLK_RES_CTRL, RT_BIT(4), RT_BIT(4), 0, APMU), + RESET_SIGNAL(VPU, APMU_VPU_CLK_RES_CTRL, RT_BIT(0), RT_BIT(0), 0, APMU), + RESET_SIGNAL(GPU, APMU_GPU_CLK_RES_CTRL, RT_BIT(1), RT_BIT(1), 0, APMU), + RESET_SIGNAL(SDH2, APMU_SDH2_CLK_RES_CTRL, RT_BIT(1), RT_BIT(1), 0, APMU), + RESET_SIGNAL(MC, APMU_PMUA_MC_CTRL, RT_BIT(0), RT_BIT(0), 0, APMU), + RESET_SIGNAL(EM_AXI, APMU_PMUA_EM_CLK_RES_CTRL, RT_BIT(0), RT_BIT(0), 0, APMU), + RESET_SIGNAL(EM, APMU_PMUA_EM_CLK_RES_CTRL, RT_BIT(1), RT_BIT(1), 0, APMU), + RESET_SIGNAL(AUDIO_SYS, APMU_AUDIO_CLK_RES_CTRL, RT_BIT(0) | RT_BIT(2) | RT_BIT(3), RT_BIT(0) | RT_BIT(2) | RT_BIT(3), 0, APMU), + RESET_SIGNAL(HDMI, APMU_HDMI_CLK_RES_CTRL, RT_BIT(9), RT_BIT(9), 0, APMU), + RESET_SIGNAL(PCIE0, APMU_PCIE_CLK_RES_CTRL_0, RT_BIT(3) | RT_BIT(4) | RT_BIT(5) | RT_BIT(8), RT_BIT(3) | RT_BIT(4) | RT_BIT(5), RT_BIT(8), APMU), + RESET_SIGNAL(PCIE1, APMU_PCIE_CLK_RES_CTRL_1, RT_BIT(3) | RT_BIT(4) | RT_BIT(5) | RT_BIT(8), RT_BIT(3) | RT_BIT(4) | RT_BIT(5), RT_BIT(8), APMU), + RESET_SIGNAL(PCIE2, APMU_PCIE_CLK_RES_CTRL_2, 0x138, 0x38, 0x100, APMU), + RESET_SIGNAL(EMAC0, APMU_EMAC0_CLK_RES_CTRL, RT_BIT(1), RT_BIT(1), 0, APMU), + RESET_SIGNAL(EMAC1, APMU_EMAC1_CLK_RES_CTRL, RT_BIT(1), RT_BIT(1), 0, APMU), + /* APBC2 */ + RESET_SIGNAL(SEC_UART1, APBC2_UART1_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC2), + RESET_SIGNAL(SEC_SSP2, APBC2_SSP2_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC2), + RESET_SIGNAL(SEC_TWSI3, APBC2_TWSI3_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC2), + RESET_SIGNAL(SEC_RTC, APBC2_RTC_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC2), + RESET_SIGNAL(SEC_TIMERS0, APBC2_TIMERS0_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC2), + RESET_SIGNAL(SEC_KPC, APBC2_KPC_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC2), + RESET_SIGNAL(SEC_GPIO, APBC2_GPIO_CLK_RST, RT_BIT(2), 0, RT_BIT(2), APBC2), + /* RCPU */ + RESET_SIGNAL(RCPU_HDMIAUDIO, RCPU_HDMI_CLK_RST, RT_BIT(0), RT_BIT(0), 0, RCPU), + RESET_SIGNAL(RCPU_CAN, RCPU_CAN_CLK_RST, RT_BIT(0), RT_BIT(0), 0, RCPU), + /* RCPU */ + RESET_SIGNAL(RCPU_I2C0, RCPU_I2C0_CLK_RST, RT_BIT(0), RT_BIT(0), 0, RCPU), + RESET_SIGNAL(RCPU_SSP0, RCPU_SSP0_CLK_RST, RT_BIT(0), RT_BIT(0), 0, RCPU), + RESET_SIGNAL(RCPU_IR, RCPU_IR_CLK_RST, RT_BIT(0), RT_BIT(0), 0, RCPU), + RESET_SIGNAL(RCPU_UART0, RCPU_UART0_CLK_RST, RT_BIT(0), RT_BIT(0), 0, RCPU), + RESET_SIGNAL(RCPU_UART1, RCPU_UART1_CLK_RST, RT_BIT(0), RT_BIT(0), 0, RCPU), + /* RCPU2 */ + RESET_SIGNAL(RCPU2_PWM0, RCPU2_PWM0_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), RCPU2), + RESET_SIGNAL(RCPU2_PWM1, RCPU2_PWM1_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), RCPU2), + RESET_SIGNAL(RCPU2_PWM2, RCPU2_PWM2_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), RCPU2), + RESET_SIGNAL(RCPU2_PWM3, RCPU2_PWM3_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), RCPU2), + RESET_SIGNAL(RCPU2_PWM4, RCPU2_PWM4_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), RCPU2), + RESET_SIGNAL(RCPU2_PWM5, RCPU2_PWM5_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), RCPU2), + RESET_SIGNAL(RCPU2_PWM6, RCPU2_PWM6_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), RCPU2), + RESET_SIGNAL(RCPU2_PWM7, RCPU2_PWM7_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), RCPU2), + RESET_SIGNAL(RCPU2_PWM8, RCPU2_PWM8_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), RCPU2), + RESET_SIGNAL(RCPU2_PWM9, RCPU2_PWM9_CLK_RST, RT_BIT(2) | RT_BIT(0), RT_BIT(0), RT_BIT(2), RCPU2), +}; + +static rt_uint32_t spacemit_reset_read(struct spacemit_reset *reset, + rt_uint32_t id) +{ + const struct spacemit_reset_signal *signal = &reset->signals[id]; + + return HWREG32(reset->mmio[signal->type] + signal->offset); +} + +static void spacemit_reset_write(struct spacemit_reset *reset, + rt_uint32_t value, rt_uint32_t id) +{ + const struct spacemit_reset_signal *signal = &reset->signals[id]; + + HWREG32(reset->mmio[signal->type] + signal->offset) = value; +} + +static void spacemit_reset_set(struct spacemit_reset *reset, + rt_uint32_t id, rt_bool_t assert) +{ + rt_uint32_t value = spacemit_reset_read(reset, id); + + value &= ~reset->signals[id].mask; + + if (assert) + { + value |=reset->signals[id].assert_val; + } + else + { + value |= reset->signals[id].deassert_val; + } + + spacemit_reset_write(reset, value, id); +} + +static rt_err_t spacemit_reset_update(struct rt_reset_control *rstc, + rt_ubase_t id, rt_bool_t assert) +{ + rt_ubase_t level; + struct spacemit_reset *reset = rstc->rstcer->priv; + + if (id == RESET_TWSI8) + { + return RT_EOK; + } + + level = rt_spin_lock_irqsave(&k1_cru_lock); + + spacemit_reset_set(reset, id, assert); + + rt_spin_unlock_irqrestore(&k1_cru_lock, level); + + return RT_EOK; +} + +static rt_err_t spacemit_reset_assert(struct rt_reset_control *rstc) +{ + return spacemit_reset_update(rstc, rstc->id, RT_TRUE); +} + +static rt_err_t spacemit_reset_deassert(struct rt_reset_control *rstc) +{ + return spacemit_reset_update(rstc, rstc->id, RT_FALSE); +} + +const static struct rt_reset_control_ops spacemit_reset_ops = +{ + .assert = spacemit_reset_assert, + .deassert = spacemit_reset_deassert, +}; + +static rt_err_t spacemit_reset_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct spacemit_reset *reset = rt_calloc(1, sizeof(*reset)); + + if (!reset) + { + return -RT_ENOMEM; + } + + for (int i = 0; i < CRU_BASE_TYPE_AUDPMU; ++i) + { + reset->mmio[i] = rt_dm_dev_iomap(dev, i); + + if (!reset->mmio[i]) + { + err = -RT_EIO; + goto _fail; + } + } + + reset->signals_nr = RT_ARRAY_SIZE(k1x_reset_signals); + reset->signals = k1x_reset_signals; + + reset->parent.priv = reset; + reset->parent.ofw_node = dev->ofw_node; + reset->parent.ops = &spacemit_reset_ops; + + if ((err = rt_reset_controller_register(&reset->parent))) + { + goto _fail; + } + + return RT_EOK; + +_fail: + for (int i = 0; i < CRU_BASE_TYPE_AUDPMU; ++i) + { + if (reset->mmio[i]) + { + rt_iounmap(reset->mmio[i]); + } + } + + rt_free(reset); + + return err; +} + +static const struct rt_ofw_node_id spacemit_reset_ofw_ids[] = +{ + { .compatible = "spacemit,k1x-reset" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_reset_driver = +{ + .name = "reset-spacemit", + .ids = spacemit_reset_ofw_ids, + + .probe = spacemit_reset_probe, +}; + +static int spacemit_reset_register(void) +{ + rt_platform_driver_register(&spacemit_reset_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(spacemit_reset_register); diff --git a/bsp/spacemit/dm/rtc/Kconfig b/bsp/spacemit/dm/rtc/Kconfig new file mode 100644 index 000000000000..cb30ec14fa2a --- /dev/null +++ b/bsp/spacemit/dm/rtc/Kconfig @@ -0,0 +1,4 @@ +config RT_RTC_SPACEMIT_PMIC + bool "Spacemit PMIC RTC" + depends on RT_MFD_SPACEMIT_PMIC + default y diff --git a/bsp/spacemit/dm/rtc/SConscript b/bsp/spacemit/dm/rtc/SConscript new file mode 100644 index 000000000000..f8c1b2efb11c --- /dev/null +++ b/bsp/spacemit/dm/rtc/SConscript @@ -0,0 +1,13 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include', cwd + '/../../../../components/drivers/rtc'] + +if GetDepend(['RT_RTC_SPACEMIT_PMIC']): + src += ['rtc-spacemit-pmic.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/rtc/rtc-spacemit-pmic.c b/bsp/spacemit/dm/rtc/rtc-spacemit-pmic.c new file mode 100644 index 000000000000..afd55640feac --- /dev/null +++ b/bsp/spacemit/dm/rtc/rtc-spacemit-pmic.c @@ -0,0 +1,592 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#define DBG_TAG "rtc.spacemit-pmic" +#define DBG_LVL DBG_INFO +#include + +#include "rtc_dm.h" + +#define __SPACEMIT_RTC_INTERNAL +#include + +#define SPACEMIT_PMIC_RTC_READ_RETRIES 10 +#define SPACEMIT_PMIC_RTC_WRITE_RETRIES 10 + +struct spacemit_pmic_rtc +{ + struct rt_device parent; + + int irq; + struct spacemit_pmic *pmic; + const struct spacemit_pmic_rtc_regdesc *desc; +}; + +#define raw_to_spacemit_pmic_rtc(raw) rt_container_of(raw, struct spacemit_pmic_rtc, parent) + +static rt_err_t spacemit_pmic_rtc_read_time(struct spacemit_pmic_rtc *pmic_rtc, time_t *sec) +{ + rt_bool_t stable = RT_FALSE; + unsigned int v[6], pre_v[6] = {0}; + struct tm tm = {0}; + struct spacemit_pmic *pmic = pmic_rtc->pmic; + + if ((signed)(pre_v[0] = spacemit_pmic_read(pmic, pmic_rtc->desc->cnt_s.reg)) < 0) + { + LOG_E("Failed to read second: %s", rt_strerror(pre_v[0])); + return -RT_EINVAL; + } + + if ((signed)(pre_v[1] = spacemit_pmic_read(pmic, pmic_rtc->desc->cnt_mi.reg)) < 0) + { + LOG_E("Failed to read minute: %s", rt_strerror(pre_v[1])); + return -RT_EINVAL; + } + + if ((signed)(pre_v[2] = spacemit_pmic_read(pmic, pmic_rtc->desc->cnt_h.reg)) < 0) + { + LOG_E("Failed to read hour: %s", rt_strerror(pre_v[2])); + return -RT_EINVAL; + } + + if ((signed)(pre_v[3] = spacemit_pmic_read(pmic, pmic_rtc->desc->cnt_d.reg)) < 0) + { + LOG_E("Failed to read day: %s", rt_strerror(pre_v[3])); + return -RT_EINVAL; + } + + if ((signed)(pre_v[4] = spacemit_pmic_read(pmic, pmic_rtc->desc->cnt_mo.reg)) < 0) + { + LOG_E("Failed to read month: %s", rt_strerror(pre_v[4])); + return -RT_EINVAL; + } + + if ((signed)(pre_v[5] = spacemit_pmic_read(pmic, pmic_rtc->desc->cnt_y.reg)) < 0) + { + LOG_E("Failed to read year: %s", rt_strerror(pre_v[5])); + return -RT_EINVAL; + } + + for (int retries = 0; retries < SPACEMIT_PMIC_RTC_READ_RETRIES; ++retries) + { + if ((signed)(v[0] = spacemit_pmic_read(pmic, pmic_rtc->desc->cnt_s.reg)) < 0) + { + LOG_E("Failed to read second: %s", rt_strerror(v[0])); + return -RT_EINVAL; + } + + if ((signed)(v[1] = spacemit_pmic_read(pmic, pmic_rtc->desc->cnt_mi.reg)) < 0) + { + LOG_E("Failed to read minute: %s", rt_strerror(v[1])); + return -RT_EINVAL; + } + + if ((signed)(v[2] = spacemit_pmic_read(pmic, pmic_rtc->desc->cnt_h.reg)) < 0) + { + LOG_E("Failed to read hour: %s", rt_strerror(v[2])); + return -RT_EINVAL; + } + + if ((signed)(v[3] = spacemit_pmic_read(pmic, pmic_rtc->desc->cnt_d.reg)) < 0) + { + LOG_E("Failed to read day: %s", rt_strerror(v[3])); + return -RT_EINVAL; + } + + if ((signed)(v[4] = spacemit_pmic_read(pmic, pmic_rtc->desc->cnt_mo.reg)) < 0) + { + LOG_E("Failed to read month: %s", rt_strerror(v[4])); + return -RT_EINVAL; + } + + if ((signed)(v[5] = spacemit_pmic_read(pmic, pmic_rtc->desc->cnt_y.reg)) < 0) + { + LOG_E("Failed to read year: %s", rt_strerror(v[5])); + return -RT_EINVAL; + } + + if ((pre_v[0] == v[0]) && (pre_v[1] == v[1]) && + (pre_v[2] == v[2]) && (pre_v[3] == v[3]) && + (pre_v[4] == v[4]) && (pre_v[5] == v[5])) + { + stable = RT_TRUE; + break; + } + else + { + pre_v[0] = v[0]; + pre_v[1] = v[1]; + pre_v[2] = v[2]; + pre_v[3] = v[3]; + pre_v[4] = v[4]; + pre_v[5] = v[5]; + } + } + + if (!stable) + { + LOG_E("RTC counter did not stabilize"); + return -RT_ETIMEOUT; + } + + tm.tm_sec = v[0] & pmic_rtc->desc->cnt_s.msk; + tm.tm_min = v[1] & pmic_rtc->desc->cnt_mi.msk; + tm.tm_hour = v[2] & pmic_rtc->desc->cnt_h.msk; + tm.tm_mday = (v[3] & pmic_rtc->desc->cnt_d.msk) + 1; + tm.tm_mon = (v[4] & pmic_rtc->desc->cnt_mo.msk); + tm.tm_year = (v[5] & pmic_rtc->desc->cnt_y.msk) + 100; + + *sec = mktime(&tm); + + return RT_EOK; +} + +static rt_err_t spacemit_pmic_rtc_set_time(struct spacemit_pmic_rtc *pmic_rtc, time_t *sec) +{ + rt_err_t err; + rt_bool_t verified = RT_FALSE; + unsigned int v[6]; + struct tm tm_buf, *tm; + union spacemit_pmic_rtc_ctl_desc rtc_ctl; + struct spacemit_pmic *pmic = pmic_rtc->pmic; + + tm = localtime_r(sec, &tm_buf); + + if (!tm) + { + return -RT_EINVAL; + } + + if ((signed)(rtc_ctl.val = spacemit_pmic_read(pmic, pmic_rtc->desc->rtc_ctl.reg)) < 0) + { + LOG_E("Failed to read rtc ctrl: %s", rt_strerror(rtc_ctl.val)); + return -RT_EINVAL; + } + + /* Disbale rtc first */ + rtc_ctl.bits.rtc_en = 0; + + if ((err = spacemit_pmic_update_bits(pmic, pmic_rtc->desc->rtc_ctl.reg, 0xff, rtc_ctl.val))) + { + LOG_E("Failed to set rtc ctrl register: %s", rt_strerror(err)); + return -RT_EINVAL; + } + + for (int retries = 0; retries < SPACEMIT_PMIC_RTC_WRITE_RETRIES; ++retries) + { + if ((err = spacemit_pmic_update_bits(pmic, + pmic_rtc->desc->cnt_s.reg, pmic_rtc->desc->cnt_s.msk, tm->tm_sec))) + { + LOG_E("Failed to update second: %s", rt_strerror(err)); + return -RT_EINVAL; + } + + if ((err = spacemit_pmic_update_bits(pmic, + pmic_rtc->desc->cnt_mi.reg, pmic_rtc->desc->cnt_mi.msk, tm->tm_min))) + { + LOG_E("Failed to update minutes: %s", rt_strerror(err)); + return -RT_EINVAL; + } + + if ((err = spacemit_pmic_update_bits(pmic, + pmic_rtc->desc->cnt_h.reg, pmic_rtc->desc->cnt_h.msk, tm->tm_hour))) + { + LOG_E("Failed to update hour: %s", rt_strerror(err)); + return -RT_EINVAL; + } + + if ((err = spacemit_pmic_update_bits(pmic, + pmic_rtc->desc->cnt_d.reg, pmic_rtc->desc->cnt_d.msk, tm->tm_mday - 1))) + { + LOG_E("Failed to update day: %s", rt_strerror(err)); + return -RT_EINVAL; + } + + if ((err = spacemit_pmic_update_bits(pmic, + pmic_rtc->desc->cnt_mo.reg, pmic_rtc->desc->cnt_mo.msk, tm->tm_mon))) + { + LOG_E("Failed to update month: %s", rt_strerror(err)); + return -RT_EINVAL; + } + + if ((err = spacemit_pmic_update_bits(pmic, + pmic_rtc->desc->cnt_y.reg, pmic_rtc->desc->cnt_y.msk, tm->tm_year - 100))) + { + LOG_E("Failed to update month: %s", rt_strerror(err)); + return -RT_EINVAL; + } + + /* Read again */ + if ((signed)(v[0] = spacemit_pmic_read(pmic, pmic_rtc->desc->cnt_s.reg)) < 0) + { + LOG_E("Failed to read second: %s", rt_strerror(v[0])); + return -RT_EINVAL; + } + v[0] = v[0] & pmic_rtc->desc->cnt_s.msk; + + if ((signed)(v[1] = spacemit_pmic_read(pmic, pmic_rtc->desc->cnt_mi.reg)) < 0) + { + LOG_E("Failed to read minute: %s", rt_strerror(v[1])); + return -RT_EINVAL; + } + v[1] = v[1] & pmic_rtc->desc->cnt_mi.msk; + + if ((signed)(v[2] = spacemit_pmic_read(pmic, pmic_rtc->desc->cnt_h.reg)) < 0) + { + LOG_E("Failed to read hour: %s", rt_strerror(v[2])); + return -RT_EINVAL; + } + v[2] = v[2] & pmic_rtc->desc->cnt_h.msk; + + if ((signed)(v[3] = spacemit_pmic_read(pmic, pmic_rtc->desc->cnt_d.reg)) < 0) + { + LOG_E("Failed to read day: %s", rt_strerror(v[3])); + return -RT_EINVAL; + } + v[3] = v[3] & pmic_rtc->desc->cnt_d.msk; + + if ((signed)(v[4] = spacemit_pmic_read(pmic, pmic_rtc->desc->cnt_mo.reg)) < 0) + { + LOG_E("Failed to read month: %s", rt_strerror(v[4])); + return -RT_EINVAL; + } + v[4] = v[4] & pmic_rtc->desc->cnt_mo.msk; + + if ((signed)(v[5] = spacemit_pmic_read(pmic, pmic_rtc->desc->cnt_y.reg)) < 0) + { + LOG_E("Failed to read year: %s", rt_strerror(v[5])); + return -RT_EINVAL; + } + v[5] = v[5] & pmic_rtc->desc->cnt_y.msk; + + if ((v[0] == (pmic_rtc->desc->cnt_s.msk & tm->tm_sec)) && + (v[1] == (pmic_rtc->desc->cnt_mi.msk & tm->tm_min)) && + (v[2] == (pmic_rtc->desc->cnt_h.msk & tm->tm_hour)) && + ((v[3] + 1) == (pmic_rtc->desc->cnt_d.msk & tm->tm_mday)) && + (v[4] == (pmic_rtc->desc->cnt_mo.msk & tm->tm_mon)) && + (v[5] == (pmic_rtc->desc->cnt_y.msk & (tm->tm_year - 100)))) + { + verified = RT_TRUE; + break; + } + } + + if (!verified) + { + LOG_E("RTC time write verification timed out"); + return -RT_ETIMEOUT; + } + + /* Enable rtc last */ + rtc_ctl.bits.rtc_en = 1; + + if ((err = spacemit_pmic_update_bits(pmic, pmic_rtc->desc->rtc_ctl.reg, 0xff, rtc_ctl.val))) + { + LOG_E("Failed to set rtc ctrl register: %s", rt_strerror(err)); + return -RT_EINVAL; + } + + return RT_EOK; +} + +static rt_err_t spacemit_pmic_rtc_read_alarm(struct spacemit_pmic_rtc *pmic_rtc, + struct rt_rtc_wkalarm *alarm) +{ + unsigned int v[6]; + union spacemit_pmic_rtc_ctl_desc rtc_ctl; + struct spacemit_pmic *pmic = pmic_rtc->pmic; + + if ((signed)(v[0] = spacemit_pmic_read(pmic, pmic_rtc->desc->alarm_s.reg)) < 0) + { + LOG_E("Failed to read alarm second: %s", rt_strerror(v[0])); + return -RT_EINVAL; + } + + if ((signed)(v[1] = spacemit_pmic_read(pmic, pmic_rtc->desc->alarm_mi.reg)) < 0) + { + LOG_E("Failed to read alarm minute: %s", rt_strerror(v[1])); + return -RT_EINVAL; + } + + if ((signed)(v[2] = spacemit_pmic_read(pmic, pmic_rtc->desc->alarm_h.reg)) < 0) + { + LOG_E("Failed to read alarm hour: %s", rt_strerror(v[2])); + return -RT_EINVAL; + } + + if ((signed)(v[3] = spacemit_pmic_read(pmic, pmic_rtc->desc->alarm_d.reg)) < 0) + { + LOG_E("Failed to read alarm day: %s", rt_strerror(v[3])); + return -RT_EINVAL; + } + + if ((signed)(v[4] = spacemit_pmic_read(pmic, pmic_rtc->desc->alarm_mo.reg)) < 0) + { + LOG_E("Failed to read alarm month: %s", rt_strerror(v[4])); + return -RT_EINVAL; + } + + if ((signed)(v[5] = spacemit_pmic_read(pmic, pmic_rtc->desc->alarm_y.reg)) < 0) + { + LOG_E("Failed to read alarm year: %s", rt_strerror(v[5])); + return -RT_EINVAL; + } + + /* 2000:1:1:0:0:0 */ + alarm->tm_sec = v[0] & pmic_rtc->desc->alarm_s.msk; + alarm->tm_min = v[1] & pmic_rtc->desc->alarm_mi.msk; + alarm->tm_hour = v[2] & pmic_rtc->desc->alarm_h.msk; + alarm->tm_mday = (v[3] & pmic_rtc->desc->alarm_d.msk) + 1; + alarm->tm_mon = (v[4] & pmic_rtc->desc->alarm_mo.msk); + alarm->tm_year = (v[5] & pmic_rtc->desc->alarm_y.msk) + 100; + + if ((signed)(rtc_ctl.val = spacemit_pmic_read(pmic, pmic_rtc->desc->rtc_ctl.reg)) < 0) + { + LOG_E("Failed to read alarm second: %s", rt_strerror(rtc_ctl.val)); + return -RT_EINVAL; + } + + alarm->enable = !!rtc_ctl.bits.alarm_en; + + return RT_EOK; +} + +static rt_err_t spacemit_pmic_rtc_set_alarm(struct spacemit_pmic_rtc *pmic_rtc, + struct rt_rtc_wkalarm *alarm) +{ + rt_err_t err; + union spacemit_pmic_rtc_ctl_desc rtc_ctl; + struct spacemit_pmic *pmic = pmic_rtc->pmic; + + /* Disable the alrm function first */ + if ((signed)(rtc_ctl.val = spacemit_pmic_read(pmic, pmic_rtc->desc->rtc_ctl.reg)) < 0) + { + LOG_E("Failed to read rtc ctrl register: %s", rt_strerror(rtc_ctl.val)); + return -RT_EINVAL; + } + + rtc_ctl.bits.alarm_en = 0; + + if ((err = spacemit_pmic_update_bits(pmic, pmic_rtc->desc->rtc_ctl.reg, 0xff, rtc_ctl.val))) + { + LOG_E("Failed to set rtc ctrl register: %s", rt_strerror(err)); + return -RT_EINVAL; + } + + if ((err = spacemit_pmic_update_bits(pmic, + pmic_rtc->desc->alarm_s.reg, pmic_rtc->desc->alarm_s.msk, alarm->tm_sec))) + { + LOG_E("Failed to update alrm second: %s", rt_strerror(err)); + return -RT_EINVAL; + } + + if ((err = spacemit_pmic_update_bits(pmic, + pmic_rtc->desc->alarm_mi.reg, pmic_rtc->desc->alarm_mi.msk, alarm->tm_min))) + { + LOG_E("Failed to update alarm minutes: %s", rt_strerror(err)); + return -RT_EINVAL; + } + + if ((err = spacemit_pmic_update_bits(pmic, + pmic_rtc->desc->alarm_h.reg, pmic_rtc->desc->alarm_h.msk, alarm->tm_hour))) + { + LOG_E("Failed to update alarm hour: %s", rt_strerror(err)); + return -RT_EINVAL; + } + + if ((err = spacemit_pmic_update_bits(pmic, + pmic_rtc->desc->alarm_d.reg, pmic_rtc->desc->alarm_d.msk, alarm->tm_mday - 1))) + { + LOG_E("Failed to update alarm day: %s", rt_strerror(err)); + return -RT_EINVAL; + } + + if ((err = spacemit_pmic_update_bits(pmic, + pmic_rtc->desc->alarm_mo.reg, pmic_rtc->desc->alarm_mo.msk, alarm->tm_mon))) + { + LOG_E("Failed to update alarm month: %s", rt_strerror(err)); + return -RT_EINVAL; + } + + if ((err = spacemit_pmic_update_bits(pmic, + pmic_rtc->desc->alarm_y.reg, pmic_rtc->desc->alarm_y.msk, alarm->tm_year - 100))) + { + LOG_E("Failed to update month: %s", rt_strerror(err)); + return -RT_EINVAL; + } + + if (alarm->enable) + { + rtc_ctl.bits.alarm_en = 1; + + if ((err = spacemit_pmic_update_bits(pmic, pmic_rtc->desc->rtc_ctl.reg, 0xff, rtc_ctl.val))) + { + LOG_E("Failed to set rtc ctrl register: %s", rt_strerror(err)); + return -RT_EINVAL; + } + } + + return RT_EOK; +} + +static rt_err_t spacemit_pmic_rtc_control(rt_device_t dev, int cmd, void *args) +{ + rt_err_t err = RT_EOK; + struct spacemit_pmic_rtc *pmic_rtc = raw_to_spacemit_pmic_rtc(dev); + + if (!args) + { + return -RT_EINVAL; + } + + switch (cmd) + { + case RT_DEVICE_CTRL_RTC_GET_TIME: + err = spacemit_pmic_rtc_read_time(pmic_rtc, args); + break; + + case RT_DEVICE_CTRL_RTC_SET_TIME: + err = spacemit_pmic_rtc_set_time(pmic_rtc, args); + break; + + case RT_DEVICE_CTRL_RTC_GET_TIMEVAL: + err = spacemit_pmic_rtc_read_time(pmic_rtc, (time_t *)&((struct timeval *)args)->tv_sec); + break; + + case RT_DEVICE_CTRL_RTC_SET_TIMEVAL: + err = spacemit_pmic_rtc_set_time(pmic_rtc, (time_t *)&((struct timeval *)args)->tv_sec); + break; + + case RT_DEVICE_CTRL_RTC_GET_ALARM: + err = spacemit_pmic_rtc_read_alarm(pmic_rtc, args); + break; + + case RT_DEVICE_CTRL_RTC_SET_ALARM: + err = spacemit_pmic_rtc_set_alarm(pmic_rtc, args); + break; + + default: + err = -RT_EINVAL; + break; + } + + return err; +} + +#ifdef RT_USING_DEVICE_OPS +const static struct rt_device_ops spacemit_pmic_rtc_ops = +{ + .control = spacemit_pmic_rtc_control, +}; +#endif + +static void spacemit_pmic_rtc_isr(int irq, void *param) +{ + struct spacemit_pmic_rtc *pmic_rtc = param; + + rt_alarm_update(&pmic_rtc->parent, 1); +} + +static rt_err_t spacemit_pmic_rtc_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + const char *dev_name; + struct rt_device *dev = &pdev->parent; + struct spacemit_pmic *pmic = pdev->priv; + union spacemit_pmic_rtc_ctl_desc rtc_ctl; + struct spacemit_pmic_rtc *pmic_rtc = rt_calloc(1, sizeof(*pmic_rtc)); + + if (!pmic_rtc) + { + return -RT_ENOMEM; + } + + pmic_rtc->pmic = pmic; + pmic_rtc->desc = pdev->id->data; + + if ((pmic_rtc->irq = rt_dm_dev_get_irq(dev, 0)) < 0) + { + err = pmic_rtc->irq; + goto _fail; + } + + /* Enable the rtc function */ + if ((signed)(rtc_ctl.val = spacemit_pmic_read(pmic, pmic_rtc->desc->rtc_ctl.reg)) < 0) + { + err = rtc_ctl.val; + goto _fail; + } + + /* Internal 32k clk */ + rtc_ctl.bits.rtc_clk_sel = 1; + /* Enable rtc */ + rtc_ctl.bits.rtc_en = 1; + /* RTC clk out enable */ + rtc_ctl.bits.out_32k_en = 1; + /* Enable external crystal */ + rtc_ctl.bits.crystal_en = 1; + + if ((err = spacemit_pmic_update_bits(pmic, pmic_rtc->desc->rtc_ctl.reg, 0xff, rtc_ctl.val))) + { + goto _fail; + } + + pmic_rtc->parent.type = RT_Device_Class_RTC; +#ifdef RT_USING_DEVICE_OPS + pmic_rtc->parent.ops = &spacemit_pmic_rtc_ops; +#else + pmic_rtc->parent.control = spacemit_pmic_rtc_control; +#endif + + rtc_dev_set_name(&pmic_rtc->parent); + dev_name = rt_dm_dev_get_name(&pmic_rtc->parent); + rt_device_register(&pmic_rtc->parent, dev_name, RT_DEVICE_FLAG_RDWR); + + rt_hw_interrupt_install(pmic_rtc->irq, spacemit_pmic_rtc_isr, pmic_rtc, "rtc-spacemit-pmic"); + rt_hw_interrupt_umask(pmic_rtc->irq); + + dev->user_data = pmic_rtc; + + return RT_EOK; +_fail: + rt_free(pmic_rtc); + + return err; +} + +static rt_err_t spacemit_pmic_rtc_remove(struct rt_platform_device *pdev) +{ + struct spacemit_pmic_rtc *pmic_rtc = pdev->parent.user_data; + + rt_hw_interrupt_mask(pmic_rtc->irq); + rt_pic_detach_irq(pmic_rtc->irq, pmic_rtc); + + rt_device_unregister(&pmic_rtc->parent); + + rt_free(pmic_rtc); + + return RT_EOK; +} + +static const struct rt_ofw_node_id spacemit_pmic_rtc_ofw_ids[] = +{ + { .compatible = "pmic,rtc,spm8821", .data = &spm8821_regdesc }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_pmic_rtc_driver = +{ + .name = "spacemit-pmic-rtc", + .ids = spacemit_pmic_rtc_ofw_ids, + + .probe = spacemit_pmic_rtc_probe, + .remove = spacemit_pmic_rtc_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(spacemit_pmic_rtc_driver); diff --git a/bsp/spacemit/dm/sdio/Kconfig b/bsp/spacemit/dm/sdio/Kconfig new file mode 100644 index 000000000000..73ed5f66e9a6 --- /dev/null +++ b/bsp/spacemit/dm/sdio/Kconfig @@ -0,0 +1,5 @@ +config RT_SDIO_SDHCI_SPACEMIT_K1X + bool "Spacemit k1x MSHC SDHCI" + depends on RT_USING_OFW + select RT_USING_SDHCI + default n diff --git a/bsp/spacemit/dm/sdio/SConscript b/bsp/spacemit/dm/sdio/SConscript new file mode 100644 index 000000000000..1974720468e0 --- /dev/null +++ b/bsp/spacemit/dm/sdio/SConscript @@ -0,0 +1,12 @@ +from building import * + +cwd = GetCurrentDir() +src = [] +CPPPATH = [cwd + '/../include', cwd + '/../../../../components/drivers/sdio'] + +if GetDepend(['RT_SDIO_SDHCI_SPACEMIT_K1X']): + src += ['sdhci-k1x.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/sdio/sdhci-k1x.c b/bsp/spacemit/dm/sdio/sdhci-k1x.c new file mode 100644 index 000000000000..91472cf2f004 --- /dev/null +++ b/bsp/spacemit/dm/sdio/sdhci-k1x.c @@ -0,0 +1,1577 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include "dev_sdio_dm.h" +#include "dev_sdhci_dm.h" + +#define DBG_TAG "sdhci.k1x" +#define DBG_LVL DBG_INFO +#include + +#define CANDIDATE_WIN_NUM 3 +#define SELECT_DELAY_NUM 9 +#define WINDOW_1ST 0 +#define WINDOW_2ND 1 +#define WINDOW_3RD 2 + +#define RX_TUNING_WINDOW_THRESHOLD 80 +#define RX_TUNING_DLINE_REG 0x09 +#define TX_TUNING_DLINE_REG 0x00 +#define TX_TUNING_DELAYCODE 127 + +#define BOOTPART_NOACC_DEFAULT 0 + +/* SDH registers define */ +#define SDHC_OP_EXT_REG 0x108 +#define OVRRD_CLK_OEN 0x0800 +#define FORCE_CLK_ON 0x1000 + +#define SDHC_LEGACY_CTRL_REG 0x10c +#define GEN_PAD_CLK_ON 0x0040 + +#define SDHC_MMC_CTRL_REG 0x114 +#define MISC_INT_EN 0x0002 +#define MISC_INT 0x0004 +#define ENHANCE_STROBE_EN 0x0100 +#define MMC_HS400 0x0200 +#define MMC_HS200 0x0400 +#define MMC_CARD_MODE 0x1000 + +#define SDHC_TX_CFG_REG 0x11c +#define TX_INT_CLK_SEL 0x40000000 +#define TX_MUX_SEL 0x80000000 + +#define SDHC_PHY_CTRL_REG 0x160 +#define PHY_FUNC_EN 0x0001 +#define PHY_PLL_LOCK 0x0002 +#define HOST_LEGACY_MODE 0x80000000 + +#define SDHC_PHY_FUNC_REG 0x164 +#define PHY_TEST_EN 0x0080 +#define HS200_USE_RFIFO 0x8000 + +#define SDHC_PHY_DLLCFG 0x168 +#define DLL_PREDLY_NUM 0x04 +#define DLL_FULLDLY_RANGE 0x10 +#define DLL_VREG_CTRL 0x40 +#define DLL_ENABLE 0x80000000 +#define DLL_REFRESH_SWEN_SHIFT 0x1c +#define DLL_REFRESH_SW_SHIFT 0x1d + +#define SDHC_PHY_DLLCFG1 0x16c +#define DLL_REG2_CTRL 0x0c +#define DLL_REG3_CTRL_MASK 0xff +#define DLL_REG3_CTRL_SHIFT 0x10 +#define DLL_REG2_CTRL_MASK 0xff +#define DLL_REG2_CTRL_SHIFT 0x08 +#define DLL_REG1_CTRL 0x92 +#define DLL_REG1_CTRL_MASK 0xff +#define DLL_REG1_CTRL_SHIFT 0x00 + +#define SDHC_PHY_DLLSTS 0x170 +#define DLL_LOCK_STATE 0x01 + +#define SDHC_PHY_DLLSTS1 0x174 +#define DLL_MASTER_DELAY_MASK 0xff +#define DLL_MASTER_DELAY_SHIFT 0x10 + +#define SDHC_PHY_PADCFG_REG 0x178 +#define RX_BIAS_CTRL_SHIFT 0x5 +#define PHY_DRIVE_SEL_SHIFT 0x0 +#define PHY_DRIVE_SEL_MASK 0x7 +#define PHY_DRIVE_SEL_DEFAULT 0x4 + +#define RPM_DELAY 50 +#define MAX_74CLK_WAIT_COUNT 100 + +#define MMC1_IO_V18EN 0x04 +#define AKEY_ASFAR 0xbaba +#define AKEY_ASSAR 0xeb10 + +/* Spacemit private quirk, shared with the DT binding. */ +#define RT_SDHCI_QUIRK2_SET_AIB_MMC RT_BIT(27) + +#define SDHC_RX_CFG_REG 0x118 +#define RX_SDCLK_SEL0_MASK 0x03 +#define RX_SDCLK_SEL0_SHIFT 0x00 +#define RX_SDCLK_SEL0 0x02 +#define RX_SDCLK_SEL1_MASK 0x03 +#define RX_SDCLK_SEL1_SHIFT 0x02 +#define RX_SDCLK_SEL1 0x01 + +#define SDHC_DLINE_CTRL_REG 0x130 +#define DLINE_PU 0x01 +#define RX_DLINE_CODE_MASK 0xff +#define RX_DLINE_CODE_SHIFT 0x10 +#define TX_DLINE_CODE_MASK 0xff +#define TX_DLINE_CODE_SHIFT 0x18 + +#define SDHC_DLINE_CFG_REG 0x134 +#define RX_DLINE_REG_MASK 0xff +#define RX_DLINE_REG_SHIFT 0x00 +#define RX_DLINE_GAIN_MASK 0x1 +#define RX_DLINE_GAIN_SHIFT 0x8 +#define RX_DLINE_GAIN 0x1 +#define TX_DLINE_REG_MASK 0xff +#define TX_DLINE_REG_SHIFT 0x10 + +#define SDHC_RX_TUNE_DELAY_MIN 0x0 +#define SDHC_RX_TUNE_DELAY_MAX 0xff +#define SDHC_RX_TUNE_DELAY_STEP 0x1 + +#define MMC_CAP2_QUIRK_BREAK_SDR104 RT_BIT(30) + +enum window_type +{ + LEFT_WINDOW = 0, + MIDDLE_WINDOW = 1, + RIGHT_WINDOW = 2, +}; + +struct tuning_window +{ + rt_uint8_t type; + rt_uint8_t min_delay; + rt_uint8_t max_delay; +}; + +struct rx_tuning +{ + rt_uint8_t rx_dline_reg; + rt_uint8_t select_delay_num; + rt_uint8_t current_delay_index; + /* 0: biggest window, 1: bigger, 2: small */ + struct tuning_window windows[CANDIDATE_WIN_NUM]; + rt_uint8_t select_delay[SELECT_DELAY_NUM]; + + rt_uint32_t card_cid[4]; + rt_uint8_t window_limit; + rt_uint8_t tuning_fail; + rt_uint8_t window_type; +}; + +struct k1x_sdhci_data +{ + rt_uint32_t host_freq; + rt_uint32_t flags; + rt_uint32_t host_caps; + rt_uint32_t host_caps2; + rt_uint32_t host_caps_disable; + rt_uint32_t host_caps2_disable; + rt_uint32_t quirks; + rt_uint32_t quirks2; + rt_uint32_t pm_caps; + + rt_uint32_t aib_mmc1_io_reg; + rt_uint32_t apbc_asfar_reg; + rt_uint32_t apbc_assar_reg; + + rt_uint8_t tx_dline_reg; + rt_uint8_t tx_delaycode; + rt_uint8_t tx_delaycode_cnt; + rt_uint8_t tx_delaycode_array[2]; + rt_uint8_t phy_driver_sel; + struct rx_tuning rxtuning; + rt_uint8_t need_reset_dllcfg1; + rt_uint32_t prev_dllcfg1; + rt_uint32_t curr_dllcfg1; + rt_uint32_t new_dllcfg1; + rt_uint8_t dllcfg1_odd_reset; + rt_uint32_t rx_tuning_freq; +}; + +struct k1x_sdhci +{ + struct rt_sdhci_host *host; + + struct rt_clk *clk_core; + struct rt_clk *clk_io; + struct rt_clk *clk_aib; + struct rt_reset_control *rstc; + unsigned char power_mode; + + rt_bool_t pinctrl; + struct k1x_sdhci_data pdata; +}; + +static const rt_uint32_t tuning_patten4[16] = +{ + 0x00ff0fff, 0xccc3ccff, 0xffcc3cc3, 0xeffefffe, + 0xddffdfff, 0xfbfffbff, 0xff7fffbf, 0xefbdf777, + 0xf0fff0ff, 0x3cccfc0f, 0xcfcc33cc, 0xeeffefff, + 0xfdfffdff, 0xffbfffdf, 0xfff7ffbb, 0xde7b7ff7, +}; + +static const rt_uint32_t tuning_patten8[32] = +{ + 0xff00ffff, 0x0000ffff, 0xccccffff, 0xcccc33cc, + 0xcc3333cc, 0xffffcccc, 0xffffeeff, 0xffeeeeff, + 0xffddffff, 0xddddffff, 0xbbffffff, 0xbbffffff, + 0xffffffbb, 0xffffff77, 0x77ff7777, 0xffeeddbb, + 0x00ffffff, 0x00ffffff, 0xccffff00, 0xcc33cccc, + 0x3333cccc, 0xffcccccc, 0xffeeffff, 0xeeeeffff, + 0xddffffff, 0xddffffff, 0xffffffdd, 0xffffffbb, + 0xffffbbbb, 0xffff77ff, 0xff7777ff, 0xeeddbb77, +}; + +static void k1x_sdhci_set_clk_gate(struct rt_sdhci_host *host, rt_bool_t auto_gate) +{ + unsigned int reg; + + reg = rt_sdhci_readl(host, SDHC_OP_EXT_REG); + if (auto_gate) + { + reg &= ~(OVRRD_CLK_OEN | FORCE_CLK_ON); + } + else + { + reg |= OVRRD_CLK_OEN | FORCE_CLK_ON; + } + rt_sdhci_writel(host, reg, SDHC_OP_EXT_REG); +} + +static rt_bool_t k1x_sdhci_card_busy(struct rt_mmc_host *mmc) +{ + rt_bool_t res; + rt_uint32_t cmd, present_state; + struct rt_sdhci_host *host = rt_mmc_priv(mmc); + + /* Check whether DAT[0] is 0 */ + present_state = rt_sdhci_readl(host, RT_SDHCI_PRESENT_STATE); + res = !(present_state & RT_SDHCI_DATA_0_LVL_MASK); + + if (host->mmc->caps2 & MMC_CAP2_NO_MMC) + { + cmd = RT_SDHCI_GET_CMD(rt_sdhci_readw(host, RT_SDHCI_COMMAND)); + if (cmd == VOLTAGE_SWITCH && host->mmc->ios.signal_voltage == MMC_SIGNAL_VOLTAGE_180) + { + /* Recover the auto clock */ + k1x_sdhci_set_clk_gate(host, RT_TRUE); + } + } + + return res; +} + +static void k1x_sdhci_enable_sdio_irq_nolock(struct rt_sdhci_host *host, rt_bool_t enable) +{ + if (!(host->flags & RT_SDHCI_DEVICE_DEAD)) + { + if (enable) + { + host->ier |= RT_SDHCI_INT_CARD_INT; + } + else + { + host->ier &= ~RT_SDHCI_INT_CARD_INT; + } + + rt_sdhci_writel(host, host->ier, RT_SDHCI_INT_ENABLE); + rt_sdhci_writel(host, host->ier, RT_SDHCI_SIGNAL_ENABLE); + } +} + +static void k1x_sdhci_enable_sdio_irq(struct rt_mmc_host *mmc, rt_bool_t enable) +{ + rt_ubase_t level; + struct rt_sdhci_host *host = rt_mmc_priv(mmc); + + level = rt_spin_lock_irqsave(&host->lock); + k1x_sdhci_enable_sdio_irq_nolock(host, enable); + rt_spin_unlock_irqrestore(&host->lock, level); +} + +static void k1x_enable_sdio_irq(struct rt_mmc_host *mmc, int enable) +{ + rt_ubase_t level; + struct rt_sdhci_host *host = rt_mmc_priv(mmc); + + k1x_sdhci_enable_sdio_irq(mmc, enable); + + /* Avoid to read the SDIO_CCCR_INTx */ + level = rt_spin_lock_irqsave(&host->lock); + mmc->sdio_irq_pending = RT_TRUE; + rt_spin_unlock_irqrestore(&host->lock, level); +} + +static void k1x_sdhci_set_clock(struct rt_sdhci_host *host, unsigned int clock) +{ + rt_uint32_t reg, cmd; + struct rt_sdhci_pltfm_host *pltfm_host = rt_sdhci_priv(host); + struct k1x_sdhci *k1x = rt_sdhci_pltfm_priv(pltfm_host); + struct rt_mmc_host *mmc = host->mmc; + + /* + * According to the SDHC_TX_CFG_REG(0x11c), + * set TX_INT_CLK_SEL to gurantee the hold time + * at default speed mode or HS/SDR12/SDR25/SDR50 mode. + */ + reg = rt_sdhci_readl(host, SDHC_TX_CFG_REG); + if (mmc->ios.timing == MMCSD_TIMING_LEGACY || + mmc->ios.timing == MMCSD_TIMING_SD_HS || + mmc->ios.timing == MMCSD_TIMING_UHS_SDR12 || + mmc->ios.timing == MMCSD_TIMING_UHS_SDR25 || + mmc->ios.timing == MMCSD_TIMING_UHS_SDR50 || + mmc->ios.timing == MMCSD_TIMING_MMC_HS) + { + reg |= TX_INT_CLK_SEL; + } + else + { + reg &= ~TX_INT_CLK_SEL; + } + rt_sdhci_writel(host, reg, SDHC_TX_CFG_REG); + + /* set pinctrl state */ + if (k1x->pinctrl) + { + if (clock >= 200000000) + { + rt_pin_ctrl_confs_apply_by_name(mmc->parent, "fast"); + } + else if (clock == 0 || host->mmc->ios.bus_width < MMC_BUS_WIDTH_4) + { + rt_pin_ctrl_confs_apply_by_name(mmc->parent, "debug"); + } + else + { + rt_pin_ctrl_confs_apply_by_name(mmc->parent, "default"); + } + } + + rt_sdhci_set_clock(host, clock); + + if (host->mmc->caps2 & MMC_CAP2_NO_MMC) + { + /* + * According to the SD spec, during a signal voltage level switch, + * the clock must be closed for 5 ms. + * then, the host starts providing clk at 1.8 and the host checks whether + * DAT[3:0] is high after 1ms clk. + * + * For the above goal, temporarily disable the auto clk + * and keep clk always on for 1ms. + */ + cmd = RT_SDHCI_GET_CMD(rt_sdhci_readw(host, RT_SDHCI_COMMAND)); + + if (cmd == VOLTAGE_SWITCH && host->mmc->ios.signal_voltage == MMC_SIGNAL_VOLTAGE_180) + { + /* Disable auto clock */ + k1x_sdhci_set_clk_gate(host, 0); + } + } +}; + +static void k1x_sdhci_phy_dll_init(struct rt_sdhci_host *host) +{ + rt_uint32_t reg; + + /* Config dll_reg1 & dll_reg2 */ + reg = rt_sdhci_readl(host, SDHC_PHY_DLLCFG); + reg |= DLL_PREDLY_NUM | DLL_FULLDLY_RANGE | DLL_VREG_CTRL; + rt_sdhci_writel(host, reg, SDHC_PHY_DLLCFG); + + reg = rt_sdhci_readl(host, SDHC_PHY_DLLCFG1); + reg |= DLL_REG1_CTRL & DLL_REG1_CTRL_MASK; + rt_sdhci_writel(host, reg, SDHC_PHY_DLLCFG1); + + /* Dll enable */ + reg = rt_sdhci_readl(host, SDHC_PHY_DLLCFG); + reg |= DLL_ENABLE; + rt_sdhci_writel(host, reg, SDHC_PHY_DLLCFG); + + /* Wait dll lock */ + for (int i = 0; i < 100; ++i) + { + if (rt_sdhci_readl(host, SDHC_PHY_DLLSTS) & DLL_LOCK_STATE) + { + break; + } + + rt_hw_us_delay(10); + } +} + +static void k1x_sdhci_hs400_enhanced_strobe(struct rt_mmc_host *mmc, struct rt_mmcsd_io_cfg *ios) +{ + rt_uint32_t reg; + struct rt_sdhci_host *host = rt_mmc_priv(mmc); + + reg = rt_sdhci_readl(host, SDHC_MMC_CTRL_REG); + if (ios->enhanced_strobe) + { + reg |= ENHANCE_STROBE_EN; + } + else + { + reg &= ~ENHANCE_STROBE_EN; + } + rt_sdhci_writel(host, reg, SDHC_MMC_CTRL_REG); + + if (ios->enhanced_strobe) + { + k1x_sdhci_phy_dll_init(host); + } +} + +static int k1x_sdhci_start_signal_voltage_switch(struct rt_mmc_host *mmc, struct rt_mmcsd_io_cfg *ios) +{ + return rt_sdhci_start_signal_voltage_switch(mmc, ios); +} + +static void k1x_sw_rx_tuning_prepare(struct rt_sdhci_host *host, rt_uint8_t dline_reg) +{ + rt_uint32_t reg; + struct rt_mmc_host *mmc = host->mmc; + struct rt_mmcsd_io_cfg ios = mmc->ios; + + reg = rt_sdhci_readl(host, SDHC_DLINE_CFG_REG); + reg &= ~(RX_DLINE_REG_MASK << RX_DLINE_REG_SHIFT); + reg |= dline_reg << RX_DLINE_REG_SHIFT; + reg &= ~(RX_DLINE_GAIN_MASK << RX_DLINE_GAIN_SHIFT); + if (ios.timing == MMC_TIMING_UHS_SDR50 && (reg & 0x40)) + { + reg |= RX_DLINE_GAIN << RX_DLINE_GAIN_SHIFT; + } + rt_sdhci_writel(host, reg, SDHC_DLINE_CFG_REG); + + reg = rt_sdhci_readl(host, SDHC_DLINE_CTRL_REG); + reg |= DLINE_PU; + rt_sdhci_writel(host, reg, SDHC_DLINE_CTRL_REG); + rt_hw_us_delay(5); + + reg = rt_sdhci_readl(host, SDHC_RX_CFG_REG); + reg &= ~(RX_SDCLK_SEL1_MASK << RX_SDCLK_SEL1_SHIFT); + reg |= RX_SDCLK_SEL1 << RX_SDCLK_SEL1_SHIFT; + rt_sdhci_writel(host, reg, SDHC_RX_CFG_REG); + + if (mmc->ios.timing == MMC_TIMING_MMC_HS200) + { + reg = rt_sdhci_readl(host, SDHC_PHY_FUNC_REG); + reg |= HS200_USE_RFIFO; + rt_sdhci_writel(host, reg, SDHC_PHY_FUNC_REG); + } +} + +static void k1x_sw_rx_set_delaycode(struct rt_sdhci_host *host, rt_uint32_t delay) +{ + rt_uint32_t reg; + + reg = rt_sdhci_readl(host, SDHC_DLINE_CTRL_REG); + reg &= ~(RX_DLINE_CODE_MASK << RX_DLINE_CODE_SHIFT); + reg |= (delay & RX_DLINE_CODE_MASK) << RX_DLINE_CODE_SHIFT; + rt_sdhci_writel(host, reg, SDHC_DLINE_CTRL_REG); +} + +static void k1x_sw_tx_tuning_prepare(struct rt_sdhci_host *host) +{ + rt_uint32_t reg; + + /* Set TX_MUX_SEL */ + reg = rt_sdhci_readl(host, SDHC_TX_CFG_REG); + reg |= TX_MUX_SEL; + rt_sdhci_writel(host, reg, SDHC_TX_CFG_REG); + + reg = rt_sdhci_readl(host, SDHC_DLINE_CTRL_REG); + reg |= DLINE_PU; + rt_sdhci_writel(host, reg, SDHC_DLINE_CTRL_REG); + + rt_hw_us_delay(5); +} + +static void k1x_sw_tx_set_dlinereg(struct rt_sdhci_host *host, rt_uint8_t dline_reg) +{ + rt_uint32_t reg; + + reg = rt_sdhci_readl(host, SDHC_DLINE_CFG_REG); + reg &= ~(TX_DLINE_REG_MASK << TX_DLINE_REG_SHIFT); + reg |= dline_reg << TX_DLINE_REG_SHIFT; + rt_sdhci_writel(host, reg, SDHC_DLINE_CFG_REG); +} + +static void k1x_sw_tx_set_delaycode(struct rt_sdhci_host *host, rt_uint32_t delay) +{ + rt_uint32_t reg; + + reg = rt_sdhci_readl(host, SDHC_DLINE_CTRL_REG); + reg &= ~(TX_DLINE_CODE_MASK << TX_DLINE_CODE_SHIFT); + reg |= (delay & TX_DLINE_CODE_MASK) << TX_DLINE_CODE_SHIFT; + rt_sdhci_writel(host, reg, SDHC_DLINE_CTRL_REG); +} + +static void k1x_sdhci_clear_set_irqs(struct rt_sdhci_host *host, rt_uint32_t clr, rt_uint32_t set) +{ + rt_uint32_t ier; + + ier = rt_sdhci_readl(host, RT_SDHCI_INT_ENABLE); + ier &= ~clr; + ier |= set; + rt_sdhci_writel(host, ier, RT_SDHCI_INT_ENABLE); + rt_sdhci_writel(host, ier, RT_SDHCI_SIGNAL_ENABLE); +} + +static int k1x_tuning_patten_check(struct rt_sdhci_host *host, int point) +{ + int patten_len, err = 0; + rt_uint32_t read_patten, *tuning_patten; + + if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_8) + { + tuning_patten = (rt_uint32_t *)tuning_patten8; + patten_len = RT_ARRAY_SIZE(tuning_patten8); + } + else + { + tuning_patten = (rt_uint32_t *)tuning_patten4; + patten_len = RT_ARRAY_SIZE(tuning_patten4); + } + + for (int i = 0; i < patten_len; ++i) + { + read_patten = rt_sdhci_readl(host, RT_SDHCI_BUFFER); + if (read_patten != tuning_patten[i]) + { + ++err; + } + } + + return err; +} + +static int k1x_send_tuning_cmd(struct rt_sdhci_host *host, rt_uint32_t opcode, + int point, rt_ubase_t level) +{ + int err = 0; + + rt_spin_unlock_irqrestore(&host->lock, level); + + rt_sdhci_send_tuning(host, opcode); + + level = rt_spin_lock_irqsave(&host->lock); + + if (!host->tuning_done) + { + LOG_E("Timeout waiting for Buffer Read Ready interrupt " + "during tuning procedure, resetting CMD and DATA"); + rt_sdhci_reset(host, RT_SDHCI_RESET_CMD | RT_SDHCI_RESET_DATA); + } + else + { + err = k1x_tuning_patten_check(host, point); + } + + host->tuning_done = 0; + + return err; +} + +static int k1x_sw_rx_select_window(struct rt_sdhci_host *host, rt_uint32_t opcode) +{ + int err = 0, min, max; + rt_uint16_t ctrl; + rt_uint32_t ier; + rt_ubase_t level = 0; + struct tuning_window tmp; + struct rt_mmc_host *mmc = host->mmc; + struct rt_sdhci_pltfm_host *pltfm_host = rt_sdhci_priv(host); + struct k1x_sdhci *k1x = rt_sdhci_pltfm_priv(pltfm_host); + struct k1x_sdhci_data *pdata = &k1x->pdata; + struct rx_tuning *rxtuning = &pdata->rxtuning; + + /* Change to pio mode during the tuning stage */ + level = rt_spin_lock_irqsave(&host->lock); + + ier = rt_sdhci_readl(host, RT_SDHCI_INT_ENABLE); + k1x_sdhci_clear_set_irqs(host, ier, RT_SDHCI_INT_DATA_AVAIL); + + min = SDHC_RX_TUNE_DELAY_MIN; + do { + /* Find the mininum delay first which can pass tuning */ + while (min < SDHC_RX_TUNE_DELAY_MAX) + { + k1x_sw_rx_set_delaycode(host, min); + + if (!mmc->ops->get_cd(mmc)) + { + rt_spin_unlock_irqrestore(&host->lock, level); + return -RT_EIO; + } + + err = k1x_send_tuning_cmd(host, opcode, min, level); + + if (err == -RT_EIO) + { + rt_spin_unlock_irqrestore(&host->lock, level); + return -RT_EIO; + } + + if (!err) + { + break; + } + + ctrl = rt_sdhci_readw(host, RT_SDHCI_HOST_CONTROL2); + ctrl &= ~(RT_SDHCI_CTRL_TUNED_CLK | RT_SDHCI_CTRL_EXEC_TUNING); + rt_sdhci_writew(host, ctrl, RT_SDHCI_HOST_CONTROL2); + min += SDHC_RX_TUNE_DELAY_STEP; + } + + /* find the maxinum delay which can not pass tuning */ + max = min + SDHC_RX_TUNE_DELAY_STEP; + + while (max < SDHC_RX_TUNE_DELAY_MAX) + { + k1x_sw_rx_set_delaycode(host, max); + if (!mmc->ops->get_cd(mmc)) + { + rt_spin_unlock_irqrestore(&host->lock, level); + return -RT_EIO; + } + + if ((err = k1x_send_tuning_cmd(host, opcode, max, level))) + { + ctrl = rt_sdhci_readw(host, RT_SDHCI_HOST_CONTROL2); + ctrl &= ~(RT_SDHCI_CTRL_TUNED_CLK | RT_SDHCI_CTRL_EXEC_TUNING); + rt_sdhci_writew(host, ctrl, RT_SDHCI_HOST_CONTROL2); + + if (err == -RT_EIO) + { + rt_spin_unlock_irqrestore(&host->lock, level); + return -RT_EIO; + } + + break; + } + max += SDHC_RX_TUNE_DELAY_STEP; + } + + /* Store the top 3 window */ + if ((max - min) >= rxtuning->window_limit) + { + tmp.max_delay = max; + tmp.min_delay = min; + tmp.type = pdata->rxtuning.window_type; + for (int i = 0; i < CANDIDATE_WIN_NUM; i++) + { + int len = rxtuning->windows[i].max_delay - rxtuning->windows[i].min_delay; + + if ((tmp.max_delay - tmp.min_delay) > len) + { + for (int j = CANDIDATE_WIN_NUM - 1; j > i; j--) + { + rxtuning->windows[j] = rxtuning->windows[j-1]; + } + + rxtuning->windows[i] = tmp; + break; + } + } + } + + min = max + SDHC_RX_TUNE_DELAY_STEP; + } while (min < SDHC_RX_TUNE_DELAY_MAX); + + k1x_sdhci_clear_set_irqs(host, RT_SDHCI_INT_DATA_AVAIL, ier); + rt_spin_unlock_irqrestore(&host->lock, level); + + return RT_EOK; +} + +static int k1x_sw_rx_select_delay(struct rt_sdhci_host *host) +{ + int win_len, min, max, mid; + struct tuning_window *window; + struct rt_sdhci_pltfm_host *pltfm_host = rt_sdhci_priv(host); + struct k1x_sdhci *k1x = rt_sdhci_pltfm_priv(pltfm_host); + struct k1x_sdhci_data *pdata = &k1x->pdata; + struct rx_tuning *tuning = &pdata->rxtuning; + + for (int i = 0; i < CANDIDATE_WIN_NUM; ++i) + { + window = &tuning->windows[i]; + min = window->min_delay; + max = window->max_delay; + mid = (min + max - 1) / 2; + win_len = max - min; + + if (win_len < tuning->window_limit) + { + continue; + } + + if (window->type == LEFT_WINDOW) + { + tuning->select_delay[tuning->select_delay_num++] = min + win_len / 4; + tuning->select_delay[tuning->select_delay_num++] = min + win_len / 3; + } + else if (window->type == RIGHT_WINDOW) + { + tuning->select_delay[tuning->select_delay_num++] = max - win_len / 4; + tuning->select_delay[tuning->select_delay_num++] = max - win_len / 3; + } + else + { + tuning->select_delay[tuning->select_delay_num++] = mid; + tuning->select_delay[tuning->select_delay_num++] = mid + win_len / 4; + tuning->select_delay[tuning->select_delay_num++] = mid - win_len / 4; + } + } + + return tuning->select_delay_num; +} + +static unsigned int k1x_sdhci_clk_get_max_clock(struct rt_sdhci_host *host) +{ + struct rt_sdhci_pltfm_host *pltfm_host = rt_sdhci_priv(host); + + return rt_clk_get_rate(pltfm_host->clk); +} + +static unsigned int k1x_get_max_timeout_count(struct rt_sdhci_host *host) +{ + /* + * The default sdhci code use the 1 << 27 as the max timeout counter + * to calculate the max_busy_timeout. + * aquilac sdhci support 1 << 29 as the timeout counter. + */ + return 1 << 29; +} + +static void k1x_sdhci_reset(struct rt_sdhci_host *host, rt_uint8_t mask) +{ + rt_uint32_t reg; + struct rt_sdhci_pltfm_host *pltfm_host = rt_sdhci_priv(host); + struct k1x_sdhci *k1x = rt_sdhci_pltfm_priv(pltfm_host); + struct k1x_sdhci_data *pdata = &k1x->pdata; + + rt_sdhci_reset(host, mask); + + if (mask != RT_SDHCI_RESET_ALL) + { + return; + } + + reg = rt_sdhci_readl(host, SDHC_PHY_CTRL_REG); + reg |= (PHY_FUNC_EN | PHY_PLL_LOCK); + rt_sdhci_writel(host, reg, SDHC_PHY_CTRL_REG); + + reg = rt_sdhci_readl(host, SDHC_PHY_PADCFG_REG); + reg |= (1 << RX_BIAS_CTRL_SHIFT); + + reg &= ~(PHY_DRIVE_SEL_MASK); + reg |= (pdata->phy_driver_sel & PHY_DRIVE_SEL_MASK) << PHY_DRIVE_SEL_SHIFT; + rt_sdhci_writel(host, reg, SDHC_PHY_PADCFG_REG); + + /* For EMMC */ + if (!(host->mmc->caps2 & MMC_CAP2_NO_MMC)) + { + /* MMC card mode */ + reg = rt_sdhci_readl(host, SDHC_MMC_CTRL_REG); + reg |= MMC_CARD_MODE; + rt_sdhci_writel(host, reg, SDHC_MMC_CTRL_REG); + } +} + +static void k1x_sdhci_set_uhs_signaling(struct rt_sdhci_host *host, unsigned timing) +{ + rt_uint16_t reg; + + if (timing == MMC_TIMING_MMC_HS200 || timing == MMC_TIMING_MMC_HS400) + { + reg = rt_sdhci_readw(host, SDHC_MMC_CTRL_REG); + reg |= (timing == MMC_TIMING_MMC_HS200) ? MMC_HS200 : MMC_HS400; + rt_sdhci_writew(host, reg, SDHC_MMC_CTRL_REG); + } + + rt_sdhci_set_uhs(host, timing); + + if (!(host->mmc->caps2 & MMC_CAP2_NO_SDIO)) + { + reg = rt_sdhci_readw(host, RT_SDHCI_HOST_CONTROL2); + rt_sdhci_writew(host, reg | RT_SDHCI_CTRL_VDD_180, RT_SDHCI_HOST_CONTROL2); + } +} + +static int k1x_sdhci_execute_sw_tuning(struct rt_sdhci_host *host, rt_uint32_t opcode) +{ + struct rt_mmc_host *mmc = host->mmc; + struct rt_mmcsd_io_cfg ios = mmc->ios; + struct rt_sdhci_pltfm_host *pltfm_host = rt_sdhci_priv(host); + struct k1x_sdhci *k1x = rt_sdhci_pltfm_priv(pltfm_host); + struct k1x_sdhci_data *pdata = &k1x->pdata; + struct rx_tuning *rxtuning = &pdata->rxtuning; + + /* + * Tuning is required for SDR50/SDR104, HS200/HS400 cards and + * if clock frequency is greater than 100MHz in these modes. + */ + if (host->clock < 100 * 1000 * 1000 || + !((ios.timing == MMC_TIMING_MMC_HS200) || + (ios.timing == MMC_TIMING_UHS_SDR50) || + (ios.timing == MMC_TIMING_UHS_SDR104))) + { + return 0; + } + + if (!(mmc->caps2 & MMC_CAP2_NO_SD) && !mmc->ops->get_cd(mmc)) + { + return 0; + } + + /* TX tuning config */ + if (host->mmc->caps2 & MMC_CAP2_NO_MMC) + { + k1x_sw_tx_set_dlinereg(host, pdata->tx_dline_reg); + k1x_sw_tx_set_delaycode(host, pdata->tx_delaycode); + k1x_sw_tx_tuning_prepare(host); + } + + rxtuning->select_delay_num = 0; + rxtuning->current_delay_index = 0; + rt_memset(rxtuning->windows, 0, sizeof(rxtuning->windows)); + rt_memset(rxtuning->select_delay, 0xFF, sizeof(rxtuning->select_delay)); + rt_memset(rxtuning->card_cid, 0, sizeof(rxtuning->card_cid)); + + /* Get pass window and caculate the select_delay */ + k1x_sw_rx_tuning_prepare(host, rxtuning->rx_dline_reg); + + if (k1x_sw_rx_select_window(host, opcode)) + { + rxtuning->tuning_fail = 1; + return -RT_EIO; + } + + if (!k1x_sw_rx_select_delay(host)) + { + rxtuning->tuning_fail = 1; + return -RT_EIO; + } + + /* Set the delay code and store card cid */ + k1x_sw_rx_set_delaycode(host, rxtuning->select_delay[0]); + rxtuning->tuning_fail = 0; + + return 0; +} + +static rt_uint32_t k1x_handle_interrupt(struct rt_sdhci_host *host, rt_uint32_t intmask) +{ + /* Handle sdio RT_SDHCI_INT_CARD_INT */ + if ((intmask & RT_SDHCI_INT_CARD_INT) && (host->ier & RT_SDHCI_INT_CARD_INT)) + { + if (!(host->flags & RT_SDHCI_DEVICE_DEAD)) + { + host->ier &= ~RT_SDHCI_INT_CARD_INT; + rt_sdhci_writel(host, host->ier, RT_SDHCI_INT_ENABLE); + rt_sdhci_writel(host, host->ier, RT_SDHCI_SIGNAL_ENABLE); + } + + /* Wakeup ksdioirqd thread */ + host->mmc->sdio_irq_pending = RT_TRUE; + if (host->mmc->rthost.sdio_irq_thread) + { + rt_thread_resume(host->mmc->rthost.sdio_irq_thread); + } + } + + /* Handle error interrupts */ + if (intmask & RT_SDHCI_INT_ERROR) + { + if (intmask & (RT_SDHCI_INT_CRC | RT_SDHCI_INT_DATA_CRC | RT_SDHCI_INT_DATA_END_BIT | RT_SDHCI_INT_AUTO_CMD_ERR)) + { + /* Handle crc error for sd device */ + if (host->mmc->caps2 & MMC_CAP2_NO_MMC) + { + host->mmc->caps2 |= MMC_CAP2_QUIRK_BREAK_SDR104; + } + } + } + + return intmask; +} + +static void k1x_set_aib_mmc1_io(struct rt_sdhci_host *host, int signal_voltage) +{ + void *aib_mmc1_io = RT_NULL; + void *apbc_asfar = RT_NULL; + void *apbc_assar = RT_NULL; + rt_uint32_t reg; + struct rt_sdhci_pltfm_host *pltfm_host = rt_sdhci_priv(host); + struct k1x_sdhci *k1x = rt_sdhci_pltfm_priv(pltfm_host); + struct k1x_sdhci_data *pdata = &k1x->pdata; + + if (!pdata->aib_mmc1_io_reg || !pdata->apbc_asfar_reg || + !pdata->apbc_assar_reg) + { + return; + } + + aib_mmc1_io = rt_ioremap((void *)(rt_ubase_t)pdata->aib_mmc1_io_reg, 4); + apbc_asfar = rt_ioremap((void *)(rt_ubase_t)pdata->apbc_asfar_reg, 4); + apbc_assar = rt_ioremap((void *)(rt_ubase_t)pdata->apbc_assar_reg, 4); + if (!aib_mmc1_io || !apbc_asfar || !apbc_assar) + { + LOG_E("Map AIB voltage control registers failed"); + goto _unmap; + } + + HWREG32(apbc_asfar) = AKEY_ASFAR; + HWREG32(apbc_assar) = AKEY_ASSAR; + reg = HWREG32(aib_mmc1_io); + + if (signal_voltage == MMC_SIGNAL_VOLTAGE_180) + { + reg |= MMC1_IO_V18EN; + } + else + { + reg &= ~MMC1_IO_V18EN; + } + + HWREG32(apbc_asfar) = AKEY_ASFAR; + HWREG32(apbc_assar) = AKEY_ASSAR; + HWREG32(aib_mmc1_io) = reg; + rt_hw_dsb(); + +_unmap: + if (apbc_assar) + { + rt_iounmap(apbc_assar); + } + if (apbc_asfar) + { + rt_iounmap(apbc_asfar); + } + if (aib_mmc1_io) + { + rt_iounmap(aib_mmc1_io); + } +} + +static void k1x_sdhci_voltage_switch(struct rt_sdhci_host *host) +{ + if (host->quirks2 & RT_SDHCI_QUIRK2_SET_AIB_MMC) + { + k1x_set_aib_mmc1_io(host, host->mmc->rthost.io_cfg.signal_voltage); + } +} + +static const struct rt_sdhci_ops k1x_sdhci_ops = +{ + .set_clock = k1x_sdhci_set_clock, + .get_max_clock = k1x_sdhci_clk_get_max_clock, + .get_max_timeout_count = k1x_get_max_timeout_count, + .set_bus_width = rt_sdhci_set_bus_width, + .reset = k1x_sdhci_reset, + .set_uhs_signaling = k1x_sdhci_set_uhs_signaling, + .platform_execute_tuning = k1x_sdhci_execute_sw_tuning, + .irq = k1x_handle_interrupt, + .set_power = rt_sdhci_set_power_and_bus_voltage, + .voltage_switch = k1x_sdhci_voltage_switch, +}; + +static int k1x_sdhci_pre_select_hs400(struct rt_mmc_host *mmc) +{ + rt_uint32_t reg; + struct rt_sdhci_host *host = rt_mmc_priv(mmc); + + reg = rt_sdhci_readl(host, SDHC_MMC_CTRL_REG); + reg |= MMC_HS400; + rt_sdhci_writel(host, reg, SDHC_MMC_CTRL_REG); + + return RT_EOK; +} + +static void k1x_sdhci_post_select_hs400(struct rt_mmc_host *mmc) +{ + struct rt_sdhci_host *host = rt_mmc_priv(mmc); + + k1x_sdhci_phy_dll_init(host); +} + +static void k1x_sdhci_pre_hs400_to_hs200(struct rt_mmc_host *mmc) +{ + rt_uint32_t reg; + struct rt_sdhci_host *host = rt_mmc_priv(mmc); + + reg = rt_sdhci_readl(host, SDHC_PHY_CTRL_REG); + reg &= ~(PHY_FUNC_EN | PHY_PLL_LOCK); + rt_sdhci_writel(host, reg, SDHC_PHY_CTRL_REG); + + reg = rt_sdhci_readl(host, SDHC_MMC_CTRL_REG); + reg &= ~(MMC_HS400 | MMC_HS200 | ENHANCE_STROBE_EN); + rt_sdhci_writel(host, reg, SDHC_MMC_CTRL_REG); + + reg = rt_sdhci_readl(host, SDHC_PHY_FUNC_REG); + reg &= ~HS200_USE_RFIFO; + rt_sdhci_writel(host, reg, SDHC_PHY_FUNC_REG); + + rt_hw_us_delay(5); + + reg = rt_sdhci_readl(host, SDHC_PHY_CTRL_REG); + reg |= PHY_FUNC_EN | PHY_PLL_LOCK; + rt_sdhci_writel(host, reg, SDHC_PHY_CTRL_REG); +} + +static struct rt_sdhci_pltfm_data sdhci_k1x_pdata = +{ + .ops = &k1x_sdhci_ops, + .quirks = RT_SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK + | RT_SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC + | RT_SDHCI_QUIRK_32BIT_ADMA_SIZE + | RT_SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, + .quirks2 = RT_SDHCI_QUIRK2_BROKEN_64_BIT_DMA, +}; + +static void k1x_sdhci_request(struct rt_mmc_host *mmc, + struct rt_mmcsd_req *mrq) +{ + struct rt_mmcsd_data *data = mrq->data; + void *original, *bounce; + rt_size_t length, alloc_length; + + if (!data || !data->buf) + { + rt_sdhci_start_request(mmc, mrq); + return; + } + + length = data->blks * data->blksize; + if (!(((rt_ubase_t)data->buf | length) & (RT_CPU_CACHE_LINE_SZ - 1))) + { + rt_sdhci_start_request(mmc, mrq); + return; + } + + alloc_length = RT_ALIGN(length, RT_CPU_CACHE_LINE_SZ); + bounce = rt_malloc_align(alloc_length, RT_CPU_CACHE_LINE_SZ); + if (!bounce) + { + mrq->cmd->err = -RT_ENOMEM; + data->err = -RT_ENOMEM; + rt_mmc_request_done(mmc, mrq); + return; + } + + original = data->buf; + if (data->flags & DATA_DIR_WRITE) + { + rt_memcpy(bounce, original, length); + } + else + { + rt_memset(bounce, 0, alloc_length); + } + + data->buf = bounce; + rt_sdhci_start_request(mmc, mrq); + rt_sem_take(&mmc->rthost.sem_ack, RT_WAITING_FOREVER); + + if ((data->flags & DATA_DIR_READ) && !mrq->cmd->err && !data->err) + { + rt_memcpy(original, bounce, length); + } + + data->buf = original; + rt_free_align(bounce); + + /* Pass the completion consumed above back to mmcsd_send_request(). */ + rt_sem_release(&mmc->rthost.sem_ack); +} + +#ifdef RT_USING_PM +static rt_err_t k1x_sdhci_pm_suspend(const struct rt_device *device, rt_uint8_t mode) +{ + rt_uint32_t reg; + rt_ubase_t level; + struct k1x_sdhci *k1x = device->user_data; + struct rt_sdhci_host *host = k1x->host; + + level = rt_spin_lock_irqsave(&host->lock); + host->runtime_suspended = RT_TRUE; + if (!(host->mmc->caps2 & MMC_CAP2_NO_MMC)) + { + reg = rt_sdhci_readl(host, SDHC_PHY_CTRL_REG); + reg &= ~PHY_FUNC_EN; + rt_sdhci_writel(host, reg, SDHC_PHY_CTRL_REG); + } + rt_spin_unlock_irqrestore(&host->lock, level); + + rt_clk_disable_unprepare(k1x->clk_io); + + if (!rt_is_err(k1x->clk_aib)) + { + rt_clk_disable_unprepare(k1x->clk_aib); + } + + if (!rt_is_err(k1x->clk_core)) + { + rt_clk_disable_unprepare(k1x->clk_core); + } + + return RT_EOK; +} + +static void k1x_sdhci_pm_resume(const struct rt_device *device, rt_uint8_t mode) +{ + rt_uint32_t reg; + rt_ubase_t level; + struct k1x_sdhci *k1x = device->user_data; + struct rt_sdhci_host *host = k1x->host; + + rt_clk_prepare_enable(k1x->clk_io); + + if (!rt_is_err(k1x->clk_aib)) + { + rt_clk_prepare_enable(k1x->clk_aib); + } + if (!rt_is_err(k1x->clk_core)) + { + rt_clk_prepare_enable(k1x->clk_core); + } + + level = rt_spin_lock_irqsave(&host->lock); + if (!(host->mmc->caps2 & MMC_CAP2_NO_MMC)) + { + reg = rt_sdhci_readl(host, SDHC_PHY_CTRL_REG); + reg |= PHY_FUNC_EN; + rt_sdhci_writel(host, reg, SDHC_PHY_CTRL_REG); + } + host->runtime_suspended = RT_FALSE; + rt_spin_unlock_irqrestore(&host->lock, level); +} + +static const struct rt_device_pm_ops k1x_sdhci_pm_ops = +{ + .suspend = k1x_sdhci_pm_suspend, + .resume = k1x_sdhci_pm_resume, +}; +#endif /* RT_USING_PM */ + +static rt_err_t k1x_sdhci_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + rt_uint32_t val; + struct k1x_sdhci *k1x; + struct k1x_sdhci_data *pdata; + struct rt_sdhci_host *host; + struct rt_sdhci_pltfm_host *pltfm_host; + struct rt_device *dev = &pdev->parent; + + host = rt_sdhci_pltfm_init(pdev, &sdhci_k1x_pdata, sizeof(*k1x)); + if (!host) + { + return -RT_ERROR; + } + + pltfm_host = rt_sdhci_priv(host); + k1x = rt_sdhci_pltfm_priv(pltfm_host); + pdata = &k1x->pdata; + + k1x->clk_io = rt_clk_get_by_name(dev, "sdh-io"); + if (rt_is_err(k1x->clk_io)) + { + k1x->clk_io = rt_clk_get_by_index(dev, 0); + } + if (rt_is_err(k1x->clk_io)) + { + err = rt_ptr_err(k1x->clk_io); + goto _fail; + } + pltfm_host->clk = k1x->clk_io; + + if ((err = rt_clk_prepare_enable(k1x->clk_io))) + { + goto _free_clk_io; + } + + k1x->clk_core = rt_clk_get_by_name(dev, "sdh-core"); + if (!rt_is_err(k1x->clk_core)) + { + if ((err = rt_clk_prepare_enable(k1x->clk_core))) + { + goto _free_clk_core; + } + } + + k1x->clk_aib = rt_clk_get_by_name(dev, "aib-clk"); + if (!rt_is_err(k1x->clk_aib)) + { + if ((err = rt_clk_prepare_enable(k1x->clk_aib))) + { + goto _free_clk_aib; + } + } + + k1x->rstc = rt_reset_control_get_by_index(dev, 0); + if (rt_is_err(k1x->rstc)) + { + err = rt_ptr_err(k1x->rstc); + goto _free_clk_aib; + } + + if ((err = rt_reset_control_deassert(k1x->rstc))) + { + goto _err_rst_get; + } + + if ((err = rt_mmc_of_parse(host->mmc))) + { + goto _err_rst_deassert; + } + + /* rt_mmc_of_parse() does not currently import this standard property. */ + if (rt_dm_dev_prop_read_bool(dev, "no-mmc")) + { + host->mmc->caps2 |= MMC_CAP2_NO_MMC; + } + + rt_sdhci_get_property(pdev); + + /* SDH io clk */ + if (!rt_dm_dev_prop_read_u32(dev, "spacemit,sdh-freq", &val)) + { + pdata->host_freq = val; + } + if (!rt_dm_dev_prop_read_u32(dev, "spacemit,sdh-flags", &val)) + { + pdata->flags |= val; + } + if (!rt_dm_dev_prop_read_u32(dev, "spacemit,sdh-host-caps", &val)) + { + pdata->host_caps |= val; + } + if (!rt_dm_dev_prop_read_u32(dev, "spacemit,sdh-host-caps2", &val)) + { + pdata->host_caps2 |= val; + } + if (!rt_dm_dev_prop_read_u32(dev, "spacemit,sdh-host-caps-disable", &val)) + { + pdata->host_caps_disable |= val; + } + if (!rt_dm_dev_prop_read_u32(dev, "spacemit,sdh-host-caps2-disable", &val)) + { + pdata->host_caps2_disable |= val; + } + if (!rt_dm_dev_prop_read_u32(dev, "spacemit,sdh-quirks", &val)) + { + pdata->quirks |= val; + } + if (!rt_dm_dev_prop_read_u32(dev, "spacemit,sdh-quirks2", &val)) + { + pdata->quirks2 |= val; + } + if (!rt_dm_dev_prop_read_u32(dev, "spacemit,aib_mmc1_io_reg", &val)) + { + pdata->aib_mmc1_io_reg = val; + } + else + { + pdata->aib_mmc1_io_reg = 0x0; + } + if (!rt_dm_dev_prop_read_u32(dev, "spacemit,apbc_asfar_reg", &val)) + { + pdata->apbc_asfar_reg = val; + } + else + { + pdata->apbc_asfar_reg = 0x0; + } + if (!rt_dm_dev_prop_read_u32(dev, "spacemit,apbc_assar_reg", &val)) + { + pdata->apbc_assar_reg = val; + } + else + { + pdata->apbc_assar_reg = 0x0; + } + /* Read rx tuning dline_reg */ + if (!rt_dm_dev_prop_read_u32(dev, "spacemit,rx_dline_reg", &val)) + { + pdata->rxtuning.rx_dline_reg = (rt_uint8_t)val; + } + else + { + pdata->rxtuning.rx_dline_reg = RX_TUNING_DLINE_REG; + } + /* Read rx tuning window limit */ + if (!rt_dm_dev_prop_read_u32(dev, "spacemit,rx_tuning_limit", &val)) + { + pdata->rxtuning.window_limit = (rt_uint8_t)val; + } + else + { + pdata->rxtuning.window_limit = RX_TUNING_WINDOW_THRESHOLD; + } + /* Read rx tuning window type */ + if (!rt_dm_dev_prop_read_u32(dev, "spacemit,rx_tuning_type", &val)) + { + pdata->rxtuning.window_type = (rt_uint8_t)val; + } + else + { + pdata->rxtuning.window_type = MIDDLE_WINDOW; + } + /* TX tuning dline_reg */ + if (!rt_dm_dev_prop_read_u32(dev, "spacemit,tx_dline_reg", &val)) + { + pdata->tx_dline_reg = (rt_uint8_t)val; + } + else + { + pdata->tx_dline_reg = TX_TUNING_DLINE_REG; + } + rt_uint32_t tx_delaycode_array[RT_ARRAY_SIZE(pdata->tx_delaycode_array)]; + int tx_delaycode_cnt = rt_dm_dev_prop_count_of_size(dev, + "spacemit,tx_delaycode", sizeof(rt_uint32_t)); + + if (tx_delaycode_cnt > 0) + { + if (tx_delaycode_cnt > RT_ARRAY_SIZE(pdata->tx_delaycode_array)) + { + tx_delaycode_cnt = RT_ARRAY_SIZE(pdata->tx_delaycode_array); + } + + if (rt_dm_dev_prop_read_u32_array_index(dev, "spacemit,tx_delaycode", + 0, tx_delaycode_cnt, tx_delaycode_array) == tx_delaycode_cnt) + { + for (int i = 0; i < tx_delaycode_cnt; ++i) + { + pdata->tx_delaycode_array[i] = tx_delaycode_array[i]; + } + pdata->tx_delaycode_cnt = tx_delaycode_cnt; + pdata->tx_delaycode = pdata->tx_delaycode_array[0]; + } + else + { + pdata->tx_delaycode_array[0] = TX_TUNING_DELAYCODE; + pdata->tx_delaycode_cnt = 1; + pdata->tx_delaycode = pdata->tx_delaycode_array[0]; + } + } + else + { + pdata->tx_delaycode_array[0] = TX_TUNING_DELAYCODE; + pdata->tx_delaycode_cnt = 1; + pdata->tx_delaycode = pdata->tx_delaycode_array[0]; + } + /* PHY driver select */ + if (!rt_dm_dev_prop_read_u32(dev, "spacemit,phy_driver_sel", &val)) + { + pdata->phy_driver_sel = (rt_uint8_t)val; + } + else + { + pdata->phy_driver_sel = PHY_DRIVE_SEL_DEFAULT; + } + /* Read rx tuning cpufreq, unit 1000Hz */ + if (!rt_dm_dev_prop_read_u32(dev, "spacemit,rx_tuning_freq", &val)) + { + pdata->rx_tuning_freq = val; + } + + if (pdata->quirks) + { + host->quirks |= pdata->quirks; + } + if (pdata->quirks2) + { + host->quirks2 |= pdata->quirks2; + } + if (pdata->host_caps) + { + host->mmc->caps |= pdata->host_caps; + } + if (pdata->host_caps2) + { + host->mmc->caps2 |= pdata->host_caps2; + } + if (pdata->pm_caps) + { + host->mmc->pm_caps |= pdata->pm_caps; + } + + if (!(host->mmc->caps2 & MMC_CAP2_NO_MMC)) + { + host->mmc_host_ops.hs400_prepare_ddr = k1x_sdhci_pre_select_hs400; + host->mmc_host_ops.hs400_complete = k1x_sdhci_post_select_hs400; + host->mmc_host_ops.hs400_downgrade = k1x_sdhci_pre_hs400_to_hs200; + if (host->mmc->caps2 & MMC_CAP2_HS400_ES) + { + host->mmc_host_ops.hs400_enhanced_strobe = k1x_sdhci_hs400_enhanced_strobe; + } + } + + if (host->mmc->caps2 & MMC_CAP2_NO_MMC) + { + /* Break sdr104 */ + if (host->mmc->caps2 & MMC_CAP2_QUIRK_BREAK_SDR104) + { + host->mmc->caps &= ~MMC_CAP_UHS_SDR104; + host->mmc->caps2 &= ~MMC_CAP2_QUIRK_BREAK_SDR104; + } + else + { + if (pdata->rxtuning.tuning_fail) + { + /* Fallback bus speed */ + host->mmc->caps &= ~MMC_CAP_UHS_SDR104; + pdata->rxtuning.tuning_fail = 0; + } + else if (!(pdata->host_caps_disable & MMC_CAP_UHS_SDR104) && + !(host->quirks2 & RT_SDHCI_QUIRK2_NO_1_8_V)) + { + /* Recovery sdr104 capability */ + host->mmc->caps |= MMC_CAP_UHS_SDR104; + } + } + } + + if (!(host->mmc->caps2 & MMC_CAP2_NO_SDIO)) + { + /* Disable MMC_CAP2_SDIO_IRQ_NOTHREAD */ + host->mmc->caps2 &= ~MMC_CAP2_SDIO_IRQ_NOTHREAD; + + /* + * Use the fake irq pending to avoid to read the SDIO_CCCR_INTx + * which sometimes return an abnormal value. + */ + host->mmc->sdio_irq_pending = RT_TRUE; + } + + host->mmc_host_ops.request = k1x_sdhci_request; + host->mmc_host_ops.start_signal_voltage_switch = k1x_sdhci_start_signal_voltage_switch; + host->mmc_host_ops.card_busy = k1x_sdhci_card_busy; + host->mmc_host_ops.enable_sdio_irq = k1x_enable_sdio_irq; + + /* Set IO clock rate */ + if (pdata->host_freq) + { + if ((err = rt_clk_set_rate(k1x->clk_io, pdata->host_freq))) + { + goto _fail; + } + } + else + { + goto _fail; + } + + if ((err = rt_sdhci_set_and_add_host(host))) + { + goto _fail; + } + + if (pdata->host_caps_disable) + { + host->mmc->caps &= ~pdata->host_caps_disable; + } + if (pdata->host_caps2_disable) + { + host->mmc->caps2 &= ~pdata->host_caps2_disable; + } + + if (host->mmc->caps2 & MMC_CAP2_NO_MMC) + { + k1x->pinctrl = RT_TRUE; + } + + dev->user_data = k1x; + +#ifdef RT_USING_PM + rt_pm_device_register(dev, &k1x_sdhci_pm_ops); +#endif + + return RT_EOK; + +_err_rst_deassert: + rt_reset_control_assert(k1x->rstc); + +_err_rst_get: + rt_reset_control_put(k1x->rstc); + k1x->rstc = RT_NULL; + + if (!rt_is_err(k1x->clk_aib)) + { + rt_clk_disable_unprepare(k1x->clk_aib); + } + +_free_clk_aib: + if (!rt_is_err(k1x->clk_aib)) + { + rt_clk_put(k1x->clk_aib); + } + k1x->clk_aib = RT_NULL; + + if (!rt_is_err(k1x->clk_core)) + { + rt_clk_disable_unprepare(k1x->clk_core); + } + +_free_clk_core: + if (!rt_is_err(k1x->clk_core)) + { + rt_clk_put(k1x->clk_core); + } + k1x->clk_core = RT_NULL; + + rt_clk_disable_unprepare(k1x->clk_io); + +_free_clk_io: + rt_clk_put(k1x->clk_io); + k1x->clk_io = RT_NULL; + +_fail: + rt_sdhci_pltfm_free(pdev); + + return err; +} + +static rt_err_t k1x_sdhci_remove(struct rt_platform_device *pdev) +{ + struct rt_sdhci_pltfm_host *pltfm_host; + struct k1x_sdhci *k1x = pdev->parent.user_data; + +#ifdef RT_USING_PM + rt_pm_device_unregister(&pdev->parent); +#endif + + pltfm_host = rt_sdhci_priv(k1x->host); + pltfm_host->clk = RT_NULL; + + rt_reset_control_assert(k1x->rstc); + + rt_clk_disable_unprepare(k1x->clk_aib); + rt_clk_disable_unprepare(k1x->clk_io); + rt_clk_disable_unprepare(k1x->clk_core); + + rt_reset_control_put(k1x->rstc); + rt_clk_put(k1x->clk_aib); + rt_clk_put(k1x->clk_io); + rt_clk_put(k1x->clk_core); + + return rt_sdhci_pltfm_remove(pdev); +} + +static const struct rt_ofw_node_id k1x_sdhci_ofw_ids[] = +{ + { .compatible = "spacemit,k1-x-sdhci" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver k1x_sdhci_driver = +{ + .name = "sdhci-iproc", + .ids = k1x_sdhci_ofw_ids, + + .probe = k1x_sdhci_probe, + .remove = k1x_sdhci_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(k1x_sdhci_driver); diff --git a/bsp/spacemit/dm/serial/8250-pxa_k1x.c b/bsp/spacemit/dm/serial/8250-pxa_k1x.c new file mode 100644 index 000000000000..dfe4d8500e66 --- /dev/null +++ b/bsp/spacemit/dm/serial/8250-pxa_k1x.c @@ -0,0 +1,362 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include +#include +#include + +#include +#include "8250/8250.h" + +#define UART_XMIT_SIZE RT_DMA_PAGE_SIZE +#define DMA_BLOCK UART_XMIT_SIZE +#define DMA_BURST_SIZE 8 + +struct serial_pxa +{ + struct serial8250 parent; + + rt_bool_t device_ctrl_rts; + + struct rt_dma_slave_config rx_config; + struct rt_dma_slave_config tx_config; + struct rt_dma_slave_transfer rx_transfer; + struct rt_dma_slave_transfer tx_transfer; + + struct rt_dma_chan *dma_rx; + struct rt_dma_chan *dma_tx; + + struct rt_clk *fclk; + struct rt_clk *gclk; + struct rt_reset_control *rstc; +}; + +#define raw_to_serial_pxa(raw) rt_container_of(raw, struct serial_pxa, parent) + +static rt_err_t serial_pxa_isr(struct serial8250 *serial, int irq) +{ + rt_uint8_t iir; + rt_uint32_t ier; + + while (!((iir = serial->serial_in(serial, UART_IIR)) & UART_IIR_NO_INT)) + { + switch (iir & UART_IIR_ID) + { + /* RX data available */ + case UART_IIR_RDI: + /* RX timeout pending */ + case UART_IIR_RX_TIMEOUT: + while (serial->serial_in(serial, UART_LSR) & UART_LSR_DR) + { + rt_hw_serial_isr(&serial->parent, RT_SERIAL_EVENT_RX_IND); + } + break; + + /* TX holding register empty */ + case UART_IIR_THRI: + ier = serial->serial_in(serial, UART_IER); + ier &= ~UART_IER_THRI; /* Disable THRI */ + serial->serial_out(serial, UART_IER, ier); + break; + + /* Line status */ + case UART_IIR_RLSI: + /* Read to clear */ + serial->serial_in(serial, UART_LSR); + break; + } + } + + return RT_EOK; +} + +static rt_err_t serial_pxa_dma_enable(struct serial8250 *serial, rt_bool_t enabled) +{ + struct serial_pxa *pxa = raw_to_serial_pxa(serial); + + if (enabled) + { + rt_dma_chan_pause(pxa->dma_rx); + rt_dma_chan_pause(pxa->dma_tx); + } + else + { + rt_dma_chan_stop(pxa->dma_rx); + rt_dma_chan_stop(pxa->dma_tx); + } + + return RT_EOK; +} + +static rt_ssize_t serial_pxa_dma_tx(struct serial8250 *serial, const rt_uint8_t *buf, rt_size_t size) +{ + rt_err_t err; + struct serial_pxa *pxa = raw_to_serial_pxa(serial); + + pxa->tx_config.src_addr = (rt_ubase_t)rt_kmem_v2p((void *)buf); + + if ((err = rt_dma_chan_config(pxa->dma_tx, &pxa->tx_config))) + { + return err; + } + + pxa->tx_transfer.buffer_len = size; + pxa->tx_transfer.src_addr = pxa->tx_config.src_addr; + + if ((err = rt_dma_prep_single(pxa->dma_tx, &pxa->tx_transfer))) + { + return err; + } + + if ((err = rt_dma_chan_start(pxa->dma_tx))) + { + return err; + } + + return size; +} + +static rt_ssize_t serial_pxa_dma_rx(struct serial8250 *serial, rt_uint8_t *buf, rt_size_t size) +{ + rt_err_t err; + struct serial_pxa *pxa = raw_to_serial_pxa(serial); + + pxa->rx_config.dst_addr = (rt_ubase_t)rt_kmem_v2p(buf); + + if ((err = rt_dma_chan_config(pxa->dma_rx, &pxa->rx_config))) + { + return err; + } + + pxa->rx_transfer.buffer_len = size; + pxa->rx_transfer.dst_addr = pxa->rx_config.dst_addr; + + if ((err = rt_dma_prep_single(pxa->dma_rx, &pxa->rx_transfer))) + { + return err; + } + + if ((err = rt_dma_chan_start(pxa->dma_rx))) + { + return err; + } + + return size; +} + +static rt_err_t serial_pxa_early_setup(struct rt_fdt_earlycon *con, const char *options) +{ + struct serial8250 *serial = &early_serial8250; + + serial->base = (void *)con->mmio; + serial->size = con->size; + serial->iotype = PORT_MMIO32; + serial->regshift = 2; + fdt_getprop_u32(con->fdt, con->nodeoffset, "reg-shift", &serial->regshift, RT_NULL); + + return serial8250_early_fdt_setup(serial, con, options); +} +RT_FDT_EARLYCON_EXPORT(serial_pxa, "uart8250", "spacemit,pxa-uart", serial_pxa_early_setup); + +static void serial_pxa_8250_remove(struct serial8250 *serial) +{ + struct serial_pxa *pxa = rt_container_of(serial, struct serial_pxa, parent); + + if (serial->base) + { + rt_iounmap(serial->base); + } + + if (!rt_is_err_or_null(pxa->rstc)) + { + rt_reset_control_assert(pxa->rstc); + rt_reset_control_put(pxa->rstc); + } + + if (!rt_is_err_or_null(pxa->fclk)) + { + rt_clk_unprepare(pxa->fclk); + rt_clk_put(pxa->fclk); + } + + if (!rt_is_err_or_null(pxa->gclk)) + { + rt_clk_unprepare(pxa->gclk); + rt_clk_put(pxa->gclk); + } + + if (!rt_is_err_or_null(pxa->dma_tx)) + { + rt_dma_chan_release(pxa->dma_tx); + } + + if (!rt_is_err_or_null(pxa->dma_rx)) + { + rt_dma_chan_release(pxa->dma_rx); + } + + rt_free(pxa); +} + +static rt_err_t serial_pxa_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + rt_ubase_t fifo_addr_phys; + struct serial8250 *serial; + struct rt_device *dev = &pdev->parent; + struct serial_pxa *pxa = serial8250_alloc(pxa); + struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT; + + if (!pxa) + { + return -RT_ENOMEM; + } + serial = &pxa->parent; + + serial->base = rt_dm_dev_iomap(dev, 0); + if (!serial->base) + { + err = -RT_EIO; + goto _fail; + } + + serial->irq = rt_dm_dev_get_irq(dev, 0); + if (serial->irq < 0) + { + err = serial->irq; + goto _fail; + } + + pxa->gclk = rt_clk_get_by_name(dev, "gate"); + if (rt_is_err(pxa->gclk)) + { + err = rt_ptr_err(pxa->gclk); + goto _fail; + } + + pxa->fclk = rt_clk_get_by_name(dev, "func"); + if (rt_is_err(pxa->fclk)) + { + err = rt_ptr_err(pxa->fclk); + goto _fail; + } + + if ((err = rt_clk_prepare(pxa->gclk))) + { + goto _fail; + } + + if ((err = rt_clk_prepare(pxa->fclk))) + { + goto _fail; + } + + pxa->rstc = rt_reset_control_get_by_index(dev, 0); + if (rt_is_err(pxa->rstc)) + { + err = rt_ptr_err(pxa->rstc); + goto _fail; + } + rt_reset_control_deassert(pxa->rstc); + + fifo_addr_phys = (rt_ubase_t)rt_kmem_v2p(serial->base); + pxa->device_ctrl_rts = rt_dm_dev_prop_read_bool(dev, "device-control-rts"); + + pxa->dma_tx = rt_dma_chan_request(dev, "tx"); + + if (!rt_is_err_or_null(pxa->dma_tx)) + { + pxa->tx_config.dst_addr_width = RT_DMA_SLAVE_BUSWIDTH_1_BYTE; + pxa->tx_config.dst_maxburst = DMA_BURST_SIZE; + pxa->tx_config.direction = RT_DMA_MEM_TO_DEV; + pxa->tx_config.dst_addr = fifo_addr_phys; + + pxa->tx_transfer.dst_addr = pxa->tx_config.dst_addr; + } + + pxa->dma_rx = rt_dma_chan_request(dev, "rx"); + + if (!rt_is_err_or_null(pxa->dma_rx)) + { + pxa->rx_config.src_addr_width = RT_DMA_SLAVE_BUSWIDTH_1_BYTE; + pxa->rx_config.src_maxburst = DMA_BURST_SIZE; + pxa->rx_config.direction = RT_DMA_DEV_TO_MEM; + pxa->rx_config.src_addr = fifo_addr_phys; + + pxa->rx_transfer.src_addr = pxa->rx_config.src_addr; + } + + serial->clk = pxa->fclk; + serial->freq = rt_clk_get_rate(pxa->fclk); + serial->regshift = 2; + serial->iotype = PORT_MMIO32; + serial->parent.ops = &serial8250_uart_ops; + serial->parent.config = config; + serial->handle_irq = serial_pxa_isr; + serial->remove = serial_pxa_8250_remove; + if (!rt_is_err_or_null(pxa->dma_rx) && !rt_is_err_or_null(pxa->dma_tx)) + { + serial->serial_dma_enable = serial_pxa_dma_enable; + serial->serial_dma_tx = serial_pxa_dma_tx; + serial->serial_dma_rx = serial_pxa_dma_rx; + } + serial->data = dev; + + if ((err = serial8250_setup(serial))) + { + goto _fail; + } + + rt_dm_dev_bind_fwdata(&serial->parent.parent, dev->ofw_node, &serial->parent); + + dev->user_data = pxa; + + return RT_EOK; + +_fail: + pxa->parent.data = dev; + serial_pxa_8250_remove(&pxa->parent); + + return err; +} + +static rt_err_t serial_pxa_remove(struct rt_platform_device *pdev) +{ + struct rt_device *dev = &pdev->parent; + struct serial8250 *serial = dev->user_data; + + rt_dm_dev_unbind_fwdata(dev, RT_NULL); + + return serial8250_remove(serial); +} + +static const struct rt_ofw_node_id serial_pxa_ofw_ids[] = +{ + { .type = "ttyS", .compatible = "spacemit,pxa-uart" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver serial_pxa_driver = +{ + .name = "serial-pxa", + .ids = serial_pxa_ofw_ids, + + .probe = serial_pxa_probe, + .remove = serial_pxa_remove, +}; + +static int serial_pxa_drv_register(void) +{ + rt_platform_driver_register(&serial_pxa_driver); + + return 0; +} +INIT_PLATFORM_EXPORT(serial_pxa_drv_register); diff --git a/bsp/spacemit/dm/serial/Kconfig b/bsp/spacemit/dm/serial/Kconfig new file mode 100644 index 000000000000..8170f85904bc --- /dev/null +++ b/bsp/spacemit/dm/serial/Kconfig @@ -0,0 +1,7 @@ +config RT_SERIAL_PXA + bool "PXA serial" + depends on RT_USING_DMA + depends on RT_SERIAL_8250 + default n + +source "$(RTT_DIR)/libcpu/risc-v/common/serial/Kconfig" diff --git a/bsp/spacemit/dm/serial/SConscript b/bsp/spacemit/dm/serial/SConscript new file mode 100644 index 000000000000..9f7f3c91f45b --- /dev/null +++ b/bsp/spacemit/dm/serial/SConscript @@ -0,0 +1,13 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include', cwd + '/../../../../components/drivers/serial/device/'] + +if GetDepend(['RT_SERIAL_PXA']): + src += ['8250-pxa_k1x.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/soc/Kconfig b/bsp/spacemit/dm/soc/Kconfig new file mode 100644 index 000000000000..f9608310d2d6 --- /dev/null +++ b/bsp/spacemit/dm/soc/Kconfig @@ -0,0 +1,33 @@ +config RT_SOC_SPACEMIT_K1X_RPROC + bool "Spacemit K1X remote processor" + depends on RT_USING_OFW + depends on RT_USING_DMA + depends on RT_USING_CLK + depends on RT_USING_RESET + depends on RT_USING_MBOX + depends on RT_USING_VIRTIO + depends on RT_USING_RPMSG + depends on RT_VIRTIO_RPMSG + default n + help + Load and control the K1X RCPU firmware and provide its VirtIO RPMsg + transport. The remote processor is started on demand by a client. + +config RT_SOC_CHIP_MEDIA_JPU + bool "Chip media JPU Driver" + default n + +config RT_SOC_SPACEMIT_V2D + bool "Spacemit V2D Engine Driver" + depends on RT_USING_OFW && RT_USING_DMA && RT_USING_CLK && RT_USING_RESET + default n + +config RT_SOC_SPACEMIT_K1X_TCM + bool "Spacemit k1x generic TCM alloc management Driver" + depends on RT_USING_MEMHEAP + default n + +config RT_SOC_SPACEMIT_SOCINFO + bool "Spacemit SoC information Driver" + depends on RT_USING_NVMEM + default n diff --git a/bsp/spacemit/dm/soc/SConscript b/bsp/spacemit/dm/soc/SConscript new file mode 100644 index 000000000000..b862bc53a4ef --- /dev/null +++ b/bsp/spacemit/dm/soc/SConscript @@ -0,0 +1,33 @@ +from building import * + +group = [] + +cwd = GetCurrentDir() +list = os.listdir(cwd) +CPPPATH = [cwd + '/../include'] + +src = [] + +if GetDepend(['RT_SOC_CHIP_MEDIA_JPU']): + src += ['jpu.c'] + +if GetDepend(['RT_SOC_SPACEMIT_K1X_RPROC']): + src += ['k1x-rproc.c'] + +if GetDepend(['RT_SOC_SPACEMIT_K1X_TCM']): + src += ['k1x-tcm.c'] + +if GetDepend(['ARCH_RISCV']): + src += ['sbi-ipi.c'] + +if GetDepend(['RT_SOC_SPACEMIT_SOCINFO']): + src += ['spacemit-socinfo.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [], CPPPATH = CPPPATH) + +for d in list: + path = os.path.join(cwd, d) + if os.path.isfile(os.path.join(path, 'SConscript')): + group = group + SConscript(os.path.join(d, 'SConscript')) + +Return('group') diff --git a/bsp/spacemit/dm/soc/jpu.c b/bsp/spacemit/dm/soc/jpu.c new file mode 100644 index 000000000000..812bd9549d32 --- /dev/null +++ b/bsp/spacemit/dm/soc/jpu.c @@ -0,0 +1,1760 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include +#include + +#define DBG_TAG "soc.spacemit.jpu" +#define DBG_LVL DBG_INFO +#include + +#include +#include +#include + +#ifndef NIEUPORT_BASE +#define NIEUPORT_BASE 0x0 +#endif + +#ifndef MMU_BASE +#define MMU_BASE 0x500 +#endif + +#define MJPEG_PIC_START_REG (NIEUPORT_BASE + 0x0000) +#define MJPEG_PIC_STATUS_REG (NIEUPORT_BASE + 0x0004) +#define MJPEG_PIC_ERRMB_REG (NIEUPORT_BASE + 0x0008) +#define MJPEG_PIC_SETMB_REG (NIEUPORT_BASE + 0x000C) + +#define MJPEG_PIC_CTRL_REG (NIEUPORT_BASE + 0x0010) +#define MJPEG_PIC_SIZE_REG (NIEUPORT_BASE + 0x0014) +#define MJPEG_MCU_INFO_REG (NIEUPORT_BASE + 0x0018) +#define MJPEG_ROT_INFO_REG (NIEUPORT_BASE + 0x001C) + +#define MJPEG_SCL_INFO_REG (NIEUPORT_BASE + 0x0020) +#define MJPEG_IF_INFO_REG (NIEUPORT_BASE + 0x0024) +#define MJPEG_CLP_INFO_REG (NIEUPORT_BASE + 0x0028) +#define MJPEG_OP_INFO_REG (NIEUPORT_BASE + 0x002C) + +#define MJPEG_DPB_CONFIG_REG (NIEUPORT_BASE + 0x0030) +#define MJPEG_DPB_BASE00_REG (NIEUPORT_BASE + 0x0034) +#define MJPEG_DPB_BASE01_REG (NIEUPORT_BASE + 0x0038) +#define MJPEG_DPB_BASE02_REG (NIEUPORT_BASE + 0x003C) +#define MJPEG_DPB_BASE10_REG (NIEUPORT_BASE + 0x0040) +#define MJPEG_DPB_BASE11_REG (NIEUPORT_BASE + 0x0044) +#define MJPEG_DPB_BASE12_REG (NIEUPORT_BASE + 0x0048) +#define MJPEG_DPB_BASE20_REG (NIEUPORT_BASE + 0x004C) +#define MJPEG_DPB_BASE21_REG (NIEUPORT_BASE + 0x0050) +#define MJPEG_DPB_BASE22_REG (NIEUPORT_BASE + 0x0054) +#define MJPEG_DPB_BASE30_REG (NIEUPORT_BASE + 0x0058) +#define MJPEG_DPB_BASE31_REG (NIEUPORT_BASE + 0x005C) +#define MJPEG_DPB_BASE32_REG (NIEUPORT_BASE + 0x0060) +#define MJPEG_DPB_YSTRIDE_REG (NIEUPORT_BASE + 0x0064) +#define MJPEG_DPB_CSTRIDE_REG (NIEUPORT_BASE + 0x0068) +#define MJPEG_WRESP_CHECK_REG (NIEUPORT_BASE + 0x006C) + +#define MJPEG_CLP_BASE_REG (NIEUPORT_BASE + 0x0070) +#define MJPEG_CLP_SIZE_REG (NIEUPORT_BASE + 0x0074) +#define MJPEG_HUFF_CTRL_REG (NIEUPORT_BASE + 0x0080) +#define MJPEG_HUFF_ADDR_REG (NIEUPORT_BASE + 0x0084) +#define MJPEG_HUFF_DATA_REG (NIEUPORT_BASE + 0x0088) +#define MJPEG_QMAT_CTRL_REG (NIEUPORT_BASE + 0x0090) +#define MJPEG_QMAT_ADDR_REG (NIEUPORT_BASE + 0x0094) +#define MJPEG_QMAT_DATA_REG (NIEUPORT_BASE + 0x0098) +#define MJPEG_COEF_CTRL_REG (NIEUPORT_BASE + 0x00A0) +#define MJPEG_COEF_ADDR_REG (NIEUPORT_BASE + 0x00A4) +#define MJPEG_COEF_DATA_REG (NIEUPORT_BASE + 0x00A8) +#define MJPEG_RST_INTVAL_REG (NIEUPORT_BASE + 0x00B0) +#define MJPEG_RST_INDEX_REG (NIEUPORT_BASE + 0x00B4) +#define MJPEG_RST_COUNT_REG (NIEUPORT_BASE + 0x00B8) +#define MJPEG_INTR_MASK_REG (NIEUPORT_BASE + 0x00C0) +#define MJPEG_CYCLE_INFO_REG (NIEUPORT_BASE + 0x00C8) +#define MJPEG_DPCM_DIFF_Y_REG (NIEUPORT_BASE + 0x00F0) +#define MJPEG_DPCM_DIFF_CB_REG (NIEUPORT_BASE + 0x00F4) +#define MJPEG_DPCM_DIFF_CR_REG (NIEUPORT_BASE + 0x00F8) + +/* GBU*/ +#define MJPEG_GBU_CTRL_REG (NIEUPORT_BASE + 0x0100) +#define MJPEG_GBU_PBIT_BUSY_REG (NIEUPORT_BASE + 0x0104) +#define MJPEG_GBU_BT_PTR_REG (NIEUPORT_BASE + 0x0110) +#define MJPEG_GBU_WD_PTR_REG (NIEUPORT_BASE + 0x0114) +#define MJPEG_GBU_TT_CNT_REG (NIEUPORT_BASE + 0x0118) +#define MJPEG_GBU_PBIT_08_REG (NIEUPORT_BASE + 0x0120) +#define MJPEG_GBU_PBIT_16_REG (NIEUPORT_BASE + 0x0124) +#define MJPEG_GBU_PBIT_24_REG (NIEUPORT_BASE + 0x0128) +#define MJPEG_GBU_PBIT_32_REG (NIEUPORT_BASE + 0x012C) +#define MJPEG_GBU_BBSR_REG (NIEUPORT_BASE + 0x0140) +#define MJPEG_GBU_BBER_REG (NIEUPORT_BASE + 0x0144) +#define MJPEG_GBU_BBIR_REG (NIEUPORT_BASE + 0x0148) +#define MJPEG_GBU_BBHR_REG (NIEUPORT_BASE + 0x014C) +#define MJPEG_GBU_BCNT_REG (NIEUPORT_BASE + 0x0158) +#define MJPEG_GBU_FF_RPTR_REG (NIEUPORT_BASE + 0x0160) +#define MJPEG_GBU_FF_WPTR_REG (NIEUPORT_BASE + 0x0164) + +/* BBC */ +#define MJPEG_BBC_END_ADDR_REG (NIEUPORT_BASE + 0x0208) +#define MJPEG_BBC_WR_PTR_REG (NIEUPORT_BASE + 0x020C) +#define MJPEG_BBC_RD_PTR_REG (NIEUPORT_BASE + 0x0210) +#define MJPEG_BBC_EXT_ADDR_REG (NIEUPORT_BASE + 0x0214) +#define MJPEG_BBC_INT_ADDR_REG (NIEUPORT_BASE + 0x0218) +#define MJPEG_BBC_DATA_CNT_REG (NIEUPORT_BASE + 0x021C) +#define MJPEG_BBC_COMMAND_REG (NIEUPORT_BASE + 0x0220) +#define MJPEG_BBC_BUSY_REG (NIEUPORT_BASE + 0x0224) +#define MJPEG_BBC_CTRL_REG (NIEUPORT_BASE + 0x0228) +#define MJPEG_BBC_CUR_POS_REG (NIEUPORT_BASE + 0x022C) +#define MJPEG_BBC_BAS_ADDR_REG (NIEUPORT_BASE + 0x0230) +#define MJPEG_BBC_STRM_CTRL_REG (NIEUPORT_BASE + 0x0234) +#define MJPEG_BBC_FLUSH_CMD_REG (NIEUPORT_BASE + 0x0238) + +#define JPU_MMU_TRI (NIEUPORT_BASE +0x400) + +#define TBU_NUM 32 +#define MJPEG_MMU_TTBLR_BASE (MMU_BASE + 0x40) +#define MJPEG_MMU_TTBHR_BASE (MMU_BASE + 0x44) +#define MJPEG_MMU_TCR0_BASE (MMU_BASE + 0x48) +#define MJPEG_MMU_TCR1_BASE (MMU_BASE + 0x4c) +#define MJPEG_MMU_TBU_STATUS_BASE (MMU_BASE + 0x50) +#define MJPEG_MMU_TBUx_STEP 0x20 +#define MJPEG_MMU_BVA_LO (MMU_BASE + 0x00) +#define MJPEG_MMU_BVA_HI (MMU_BASE + 0x04) +#define MJPEG_MMU_TIMEOUT_VA_ADDR_LO (MMU_BASE + 0x08) +#define MJPEG_MMU_TIMEOUT_VA_ADDR_HI (MMU_BASE + 0x0C) +#define MJPEG_MMU_IRQ_STATUS (MMU_BASE + 0x10) +#define MJPEG_MMU_IRQ_ENABLE (MMU_BASE + 0x14) +#define MJPEG_MMU_TIMEOUT_VALUE (MMU_BASE + 0x18) +#define MJPEG_MMU_ERROR_CLEAR (MMU_BASE + 0x1C) +#define MJPEG_MMU_LAST_VA_ADDR_LO (MMU_BASE + 0x20) +#define MJPEG_MMU_LAST_VA_ADDR_HI (MMU_BASE + 0x24) +#define MJPEG_MMU_LAST_PA_ADDR_LO (MMU_BASE + 0x28) +#define MJPEG_MMU_LAST_PA_ADDR_HI (MMU_BASE + 0x2C) +#define MJPEG_MMU_VERSION (MMU_BASE + 0x3C) + +#define MAX_ENTRIES_PER_TTB 8096 +#define ENTRY_SIZE 4 +#define MAX_SIZE_PER_TTB (MAX_ENTRIES_PER_TTB*ENTRY_SIZE) +#define DEFAULT_TIMEOUT_CYCS 0x80000 + +#define TBU_INSTANCES_NUM 2 + +#define TTB_ENTRY_SHIFT 12 +#define AQUIRE_TIMEOUT_MS 100 + +#define JPU_TIMEOUT_MS 5000 +#define JPU_BBC_TIMEOUT_US 10000 +#define JPU_ALIGN(value, align) (((value) + (align) - 1) & ~((align) - 1)) +#define JPU_BBC_PAGE_SIZE 256U + +#define JPU_TBU_INPUT 0 +#define JPU_TBU_OUTPUT 1 + +#define JPU_TBU_BASE_VA 0x80000000 +#define JPU_TBU_VA_STEP 0x2000000 + +#define JPU_INT_FATAL_MASK (RT_BIT(JPU_INT_ERROR) | \ + RT_BIT(JPU_INT_OVERFLOW)) + +#define JPU_DECODE_REG_NUM ((MJPEG_BBC_STRM_CTRL_REG / sizeof(rt_uint32_t)) + 1) + +enum spacemit_jpu_int_reason +{ + JPU_INT_DONE = 0, + JPU_INT_ERROR, + JPU_INT_BIT_BUF_EMPTY, + JPU_INT_OVERFLOW = 3, +}; + +struct spacemit_jpu_map +{ + rt_ubase_t stream_phys; + rt_ubase_t frame_phys; + rt_size_t stream_size; + rt_size_t frame_size; + rt_ubase_t stream_iova; + rt_ubase_t frame_iova; +}; + +struct spacemit_jpu_tbu +{ + rt_uint32_t *ttb_va; + rt_ubase_t ttb_pa; + rt_size_t ttb_size; + rt_ubase_t va_base; + rt_ubase_t va_end; +}; + +struct spacemit_jpu +{ + struct rt_device parent; + + struct rt_device *dev; + void *regs; + int irq; + + struct rt_clk *cclk; + struct rt_clk *aclk; + struct rt_clk *iclk; + + struct rt_reset_control *jpg_reset; + struct rt_reset_control *lcd_mclk_reset; + struct rt_reset_control *isp_ci_reset; + struct rt_reset_control *freset; + struct rt_reset_control *sreset; + + struct spacemit_jpu_tbu tbu[TBU_INSTANCES_NUM]; + rt_uint32_t page_size; + rt_ubase_t va_base; + rt_uint32_t time_out_cycs; + rt_bool_t mmu_enable; + + rt_uint32_t irq_reason; + rt_err_t error; + struct rt_completion completion; + struct rt_mutex lock; + struct rt_spinlock hw_lock; +}; + +#define raw_to_spacemit_jpu(raw) rt_container_of(raw, struct spacemit_jpu, parent) + +rt_inline rt_uint32_t spacemit_jpu_read(struct spacemit_jpu *jpu, int offset) +{ + return HWREG32(jpu->regs + offset); +} + +rt_inline void spacemit_jpu_write(struct spacemit_jpu *jpu, int offset, rt_uint32_t val) +{ + HWREG32(jpu->regs + offset) = val; +} + +rt_inline void spacemit_jpu_set_bits(struct spacemit_jpu *jpu, int offset, rt_uint32_t bits) +{ + spacemit_jpu_write(jpu, offset, spacemit_jpu_read(jpu, offset) | bits); +} + +rt_inline void spacemit_jpu_clear_bits(struct spacemit_jpu *jpu, int offset, rt_uint32_t bits) +{ + spacemit_jpu_write(jpu, offset, spacemit_jpu_read(jpu, offset) & ~bits); +} + +static rt_err_t spacemit_jpu_clk_enable(struct spacemit_jpu *jpu) +{ + rt_err_t err; + + if (!rt_is_err_or_null(jpu->cclk)) + { + err = rt_clk_prepare_enable(jpu->cclk); + if (err) + { + return err; + } + } + if (!rt_is_err_or_null(jpu->aclk)) + { + err = rt_clk_prepare_enable(jpu->aclk); + if (err) + { + return err; + } + } + if (!rt_is_err_or_null(jpu->iclk)) + { + err = rt_clk_prepare_enable(jpu->iclk); + if (err) + { + return err; + } + } + + return RT_EOK; +} + +static void spacemit_jpu_clk_disable(struct spacemit_jpu *jpu) +{ + if (!rt_is_err_or_null(jpu->iclk)) + { + rt_clk_disable_unprepare(jpu->iclk); + } + if (!rt_is_err_or_null(jpu->aclk)) + { + rt_clk_disable_unprepare(jpu->aclk); + } + if (!rt_is_err_or_null(jpu->cclk)) + { + rt_clk_disable_unprepare(jpu->cclk); + } +} + +static void spacemit_jpu_reset_assert_all(struct spacemit_jpu *jpu) +{ + if (!rt_is_err_or_null(jpu->jpg_reset)) + { + rt_reset_control_assert(jpu->jpg_reset); + } + if (!rt_is_err_or_null(jpu->lcd_mclk_reset)) + { + rt_reset_control_assert(jpu->lcd_mclk_reset); + } + if (!rt_is_err_or_null(jpu->isp_ci_reset)) + { + rt_reset_control_assert(jpu->isp_ci_reset); + } + if (!rt_is_err_or_null(jpu->freset)) + { + rt_reset_control_assert(jpu->freset); + } + if (!rt_is_err_or_null(jpu->sreset)) + { + rt_reset_control_assert(jpu->sreset); + } +} + +static void spacemit_jpu_reset_deassert_all(struct spacemit_jpu *jpu) +{ + if (!rt_is_err_or_null(jpu->jpg_reset)) + { + rt_reset_control_deassert(jpu->jpg_reset); + } + if (!rt_is_err_or_null(jpu->lcd_mclk_reset)) + { + rt_reset_control_deassert(jpu->lcd_mclk_reset); + } + if (!rt_is_err_or_null(jpu->isp_ci_reset)) + { + rt_reset_control_deassert(jpu->isp_ci_reset); + } + if (!rt_is_err_or_null(jpu->freset)) + { + rt_reset_control_deassert(jpu->freset); + } + if (!rt_is_err_or_null(jpu->sreset)) + { + rt_reset_control_deassert(jpu->sreset); + } +} + +static void spacemit_jpu_enable_mmu_hw(struct spacemit_jpu *jpu); +static void spacemit_jpu_disable_mmu_hw(struct spacemit_jpu *jpu); + +static void spacemit_jpu_hard_reset(struct spacemit_jpu *jpu) +{ + spacemit_jpu_clk_disable(jpu); + spacemit_jpu_reset_assert_all(jpu); + rt_hw_us_delay(5); + spacemit_jpu_reset_deassert_all(jpu); + spacemit_jpu_clk_enable(jpu); + spacemit_jpu_write(jpu, MJPEG_PIC_STATUS_REG, 0); +} + +static rt_err_t spacemit_jpu_sw_reset(struct spacemit_jpu *jpu) +{ + int timeout = JPU_BBC_TIMEOUT_US; + + spacemit_jpu_write(jpu, MJPEG_PIC_START_REG, RT_BIT(1)); + while (spacemit_jpu_read(jpu, MJPEG_PIC_START_REG) & RT_BIT(1)) + { + if (--timeout == 0) + { + LOG_E("JPU software reset timeout"); + return -RT_ETIMEOUT; + } + rt_hw_us_delay(1); + } + + return RT_EOK; +} + +static void spacemit_jpu_write_tbu_table(struct spacemit_jpu *jpu, + struct spacemit_jpu_tbu *tbu, rt_ubase_t iova, rt_ubase_t paddr, rt_size_t size) +{ + rt_uint32_t *ttb_entry; + rt_size_t pages; + rt_ubase_t mask; + rt_uint32_t val; + + mask = (jpu->page_size == 4096) ? 0xFFFFFFFFFFFFF000ULL : 0xFFFFFFFFFFFF0000ULL; + ttb_entry = tbu->ttb_va + (iova - tbu->va_base) / jpu->page_size; + + pages = RT_DIV_ROUND_UP(size, jpu->page_size); + while (pages-- != 0) + { + val = (rt_uint32_t)(((paddr & mask) >> TTB_ENTRY_SHIFT) & 0x1FFFFF); + *ttb_entry = val; + ttb_entry++; + paddr += jpu->page_size; + } +} + +static void spacemit_jpu_mmu_post(struct spacemit_jpu *jpu, int tbu_id) +{ + struct spacemit_jpu_tbu *tbu = &jpu->tbu[tbu_id]; + rt_uint32_t reg; + int index; + + if (!jpu->mmu_enable) + { + return; + } + + index = (tbu->va_base - jpu->va_base) / JPU_TBU_VA_STEP; + + if (tbu->ttb_size == 0) + { + spacemit_jpu_write(jpu, MJPEG_MMU_TCR0_BASE + index * MJPEG_MMU_TBUx_STEP, 0); + return; + } + + spacemit_jpu_write(jpu, MJPEG_MMU_TTBLR_BASE + index * MJPEG_MMU_TBUx_STEP, + (rt_uint32_t)(tbu->ttb_pa & 0xFFFFFFFF)); + spacemit_jpu_write(jpu, MJPEG_MMU_TTBHR_BASE + index * MJPEG_MMU_TBUx_STEP, + (rt_uint32_t)(tbu->ttb_pa >> 32)); + + reg = (rt_uint32_t)((tbu->ttb_size - 1) << 16); + reg |= RT_BIT(2); + if (jpu->page_size == 64 * 1024) + { + reg |= RT_BIT(1); + } + reg |= RT_BIT(0); + + spacemit_jpu_write(jpu, MJPEG_MMU_TCR0_BASE + index * MJPEG_MMU_TBUx_STEP, reg); +} + +static rt_err_t spacemit_jpu_mmu_map_one(struct spacemit_jpu *jpu, int tbu_id, + rt_ubase_t phys, rt_ubase_t iova, rt_size_t size, rt_ubase_t *mapped_iova) +{ + struct spacemit_jpu_tbu *tbu = &jpu->tbu[tbu_id]; + int index; + rt_ubase_t end; + + if (!size || !phys) + { + return -RT_EINVAL; + } + + if (!jpu->mmu_enable) + { + spacemit_jpu_enable_mmu_hw(jpu); + } + + index = (iova - jpu->va_base) / JPU_TBU_VA_STEP; + tbu->va_base = jpu->va_base + index * JPU_TBU_VA_STEP; + tbu->va_end = tbu->va_base + JPU_TBU_VA_STEP; + + if (iova < tbu->va_base || iova >= tbu->va_end) + { + return -RT_EINVAL; + } + + end = iova + size; + if (end > tbu->va_end) + { + return -RT_EINVAL; + } + + if (!is_aligned(phys, jpu->page_size)) + { + LOG_E("MMU map phys 0x%llx is not page aligned", (unsigned long long)phys); + return -RT_EINVAL; + } + + if (RT_DIV_ROUND_UP(end - tbu->va_base, jpu->page_size) > MAX_ENTRIES_PER_TTB) + { + return -RT_EINVAL; + } + + rt_spin_lock(&jpu->hw_lock); + spacemit_jpu_write_tbu_table(jpu, tbu, iova, phys, size); + + if (end > tbu->va_base + jpu->page_size * tbu->ttb_size) + { + tbu->ttb_size = RT_DIV_ROUND_UP(end - tbu->va_base, jpu->page_size); + } + + spacemit_jpu_mmu_post(jpu, tbu_id); + rt_spin_unlock(&jpu->hw_lock); + + *mapped_iova = iova; + return RT_EOK; +} + +static void spacemit_jpu_enable_mmu_hw(struct spacemit_jpu *jpu) +{ + int i; + + if (jpu->mmu_enable) + { + return; + } + + for (i = 0; i < TBU_INSTANCES_NUM; i++) + { + jpu->tbu[i].ttb_size = 0; + } + + spacemit_jpu_write(jpu, MJPEG_MMU_BVA_LO, (rt_uint32_t)(jpu->va_base & 0xFFFFFFFF)); + spacemit_jpu_write(jpu, MJPEG_MMU_BVA_HI, (rt_uint32_t)(jpu->va_base >> 32)); + spacemit_jpu_write(jpu, MJPEG_MMU_TIMEOUT_VALUE, jpu->time_out_cycs); + spacemit_jpu_set_bits(jpu, MJPEG_MMU_IRQ_ENABLE, 0); + + jpu->mmu_enable = RT_TRUE; +} + +static void spacemit_jpu_disable_mmu_hw(struct spacemit_jpu *jpu) +{ + int i; + + if (!jpu->mmu_enable) + { + return; + } + + rt_spin_lock(&jpu->hw_lock); + jpu->mmu_enable = RT_FALSE; + + for (i = 0; i < TBU_INSTANCES_NUM; i++) + { + jpu->tbu[i].ttb_size = 0; + } + + for (i = 0; i < TBU_NUM; i++) + { + spacemit_jpu_write(jpu, MJPEG_MMU_TCR0_BASE + MJPEG_MMU_TBUx_STEP * i, 0); + } + + spacemit_jpu_clear_bits(jpu, MJPEG_MMU_IRQ_ENABLE, 0x1FF); + rt_spin_unlock(&jpu->hw_lock); +} + +static rt_err_t spacemit_jpu_mmu_map(struct spacemit_jpu *jpu, + struct spacemit_jpu_map *map) +{ + rt_err_t err; + rt_ubase_t stream_iova = JPU_TBU_BASE_VA + JPU_TBU_INPUT * JPU_TBU_VA_STEP; + rt_ubase_t frame_iova = JPU_TBU_BASE_VA + JPU_TBU_OUTPUT * JPU_TBU_VA_STEP; + rt_uint64_t stream_end; + rt_uint64_t frame_end; + + if (!map) + { + return -RT_EINVAL; + } + + stream_end = (rt_uint64_t)map->stream_phys + map->stream_size; + frame_end = (rt_uint64_t)map->frame_phys + map->frame_size; + if (stream_end > map->stream_phys && frame_end > map->frame_phys && + stream_end <= (rt_uint64_t)UINT32_MAX + 1 && + frame_end <= (rt_uint64_t)UINT32_MAX + 1) + { + /* Bypasses the JPU MMU for a single contiguous DMA segment. */ + spacemit_jpu_disable_mmu_hw(jpu); + map->stream_iova = map->stream_phys; + map->frame_iova = map->frame_phys; + return RT_EOK; + } + + err = spacemit_jpu_mmu_map_one(jpu, JPU_TBU_INPUT, map->stream_phys, + stream_iova, map->stream_size, &stream_iova); + if (err != RT_EOK) + { + spacemit_jpu_disable_mmu_hw(jpu); + return err; + } + + err = spacemit_jpu_mmu_map_one(jpu, JPU_TBU_OUTPUT, map->frame_phys, + frame_iova, map->frame_size, &frame_iova); + if (err != RT_EOK) + { + spacemit_jpu_disable_mmu_hw(jpu); + return err; + } + + spacemit_jpu_write(jpu, JPU_MMU_TRI, 0x01); + + map->stream_iova = stream_iova; + map->frame_iova = frame_iova; + + return RT_EOK; +} + +static rt_err_t spacemit_jpu_buffer_alloc(struct spacemit_jpu *jpu, struct jpu_buffer *buf) +{ + rt_ubase_t phys_addr; + + if (!buf || !buf->size) + { + return -RT_EINVAL; + } + + buf->virt_addr = rt_dma_alloc_coherent(jpu->dev, buf->size, &phys_addr); + if (!buf->virt_addr) + { + return -RT_ENOMEM; + } + + buf->phys_addr = phys_addr; + + return RT_EOK; +} + +static rt_err_t spacemit_jpu_buffer_free(struct spacemit_jpu *jpu, struct jpu_buffer *buf) +{ + if (!buf || !buf->virt_addr) + { + return -RT_EINVAL; + } + + rt_dma_free_coherent(jpu->dev, buf->size, buf->virt_addr, buf->phys_addr); + buf->virt_addr = RT_NULL; + buf->phys_addr = 0; + + return RT_EOK; +} + +static rt_err_t spacemit_jpu_query_frame(struct jpu_frame_info *frame) +{ + rt_uint32_t aligned_width; + rt_uint32_t aligned_height; + rt_uint32_t y_stride; + rt_uint32_t c_stride; + rt_uint32_t c_height; + rt_uint64_t size; + + if (!frame || !frame->width || !frame->height) + { + return -RT_EINVAL; + } + + switch (frame->format) + { + case JPU_FORMAT_420: + aligned_width = JPU_ALIGN(frame->width, 16); + aligned_height = JPU_ALIGN(frame->height, 16); + y_stride = JPU_ALIGN(aligned_width, 8); + c_stride = JPU_ALIGN(y_stride / 2, 16); + c_height = JPU_ALIGN(aligned_height / 2, 8); + break; + case JPU_FORMAT_422: + aligned_width = JPU_ALIGN(frame->width, 16); + aligned_height = JPU_ALIGN(frame->height, 8); + y_stride = JPU_ALIGN(aligned_width, 8); + c_stride = JPU_ALIGN(y_stride / 2, 16); + c_height = JPU_ALIGN(aligned_height, 8); + break; + case JPU_FORMAT_440: + aligned_width = JPU_ALIGN(frame->width, 8); + aligned_height = JPU_ALIGN(frame->height, 16); + y_stride = JPU_ALIGN(aligned_width, 8); + c_stride = JPU_ALIGN(y_stride, 8); + c_height = JPU_ALIGN(aligned_height / 2, 8); + break; + case JPU_FORMAT_444: + aligned_width = JPU_ALIGN(frame->width, 8); + aligned_height = JPU_ALIGN(frame->height, 8); + y_stride = JPU_ALIGN(aligned_width, 8); + c_stride = JPU_ALIGN(y_stride, 8); + c_height = JPU_ALIGN(aligned_height, 8); + break; + case JPU_FORMAT_400: + aligned_width = JPU_ALIGN(frame->width, 8); + aligned_height = JPU_ALIGN(frame->height, 8); + y_stride = JPU_ALIGN(aligned_width, 8); + c_stride = 0; + c_height = 0; + break; + default: + return -RT_EINVAL; + } + + if (aligned_width > UINT16_MAX || aligned_height > UINT16_MAX || + y_stride > UINT16_MAX || c_stride > UINT16_MAX || c_height > UINT16_MAX) + { + return -RT_EINVAL; + } + + size = (rt_uint64_t)y_stride * aligned_height + + (rt_uint64_t)c_stride * c_height * 2; + if (!size || size > JPU_BUFFER_MAX_SIZE) + { + return -RT_ENOMEM; + } + + frame->aligned_width = aligned_width; + frame->aligned_height = aligned_height; + frame->y_stride = y_stride; + frame->c_stride = c_stride; + frame->c_height = c_height; + frame->size = size; + + return RT_EOK; +} + +static rt_err_t spacemit_jpu_validate_decode(struct jpu_decode_request *req) +{ + int component; + rt_err_t err; + + if (!req || !req->stream_phys || !req->frame_phys || + !req->stream_size || req->entropy_offset >= req->stream_size || + req->stream_capacity > JPU_BUFFER_MAX_SIZE || + req->frame_capacity > JPU_BUFFER_MAX_SIZE || + req->stream_size > req->stream_capacity || + JPU_STREAM_PADDING > req->stream_capacity - req->stream_size) + { + return -RT_EINVAL; + } + + if ((req->frame.format == JPU_FORMAT_400 && req->components != 1) || + (req->frame.format != JPU_FORMAT_400 && req->components != 3)) + { + return -RT_EINVAL; + } + + for (component = 0; component < req->components; ++component) + { + if (req->dc_selector[component] > 1 || req->ac_selector[component] > 1) + { + return -RT_EINVAL; + } + } + + if ((err = spacemit_jpu_query_frame(&req->frame)) != RT_EOK) + { + return err; + } + if (req->frame_capacity < req->frame.size) + { + return -RT_ENOMEM; + } + + return RT_EOK; +} + +static const rt_uint8_t jpu_default_huff_bits[JPU_HUFF_TABLE_NUM][JPU_HUFF_BITS_NUM] = +{ + { 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, + 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d }, + { 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, + 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77 }, +}; + +static const rt_uint8_t jpu_default_huff_values[JPU_HUFF_TABLE_NUM][JPU_HUFF_VALUES_NUM] = +{ + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, + }, + { + 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, + 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, + 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, + 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, + 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, + 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, + 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, + 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, + 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, + 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, + 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, + 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, + 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, + 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa, + }, + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, + }, + { + 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, + 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, + 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, + 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, + 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, + 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, + 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, + 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, + 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, + 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, + 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, + 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, + 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, + 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, + 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, + 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, + 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, + 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa, + }, +}; + +static rt_bool_t spacemit_jpu_uses_default_huffman(const struct jpu_decode_request *req) +{ + rt_bool_t checked[JPU_HUFF_TABLE_NUM] = { RT_FALSE }; + int component; + + for (component = 0; component < req->components; ++component) + { + int tables[2] = + { + req->dc_selector[component] * 2, + req->ac_selector[component] * 2 + 1, + }; + int type; + + for (type = 0; type < 2; ++type) + { + int index = tables[type]; + int count = 0; + int i; + + if (checked[index]) + { + continue; + } + checked[index] = RT_TRUE; + + for (i = 0; i < JPU_HUFF_BITS_NUM; ++i) + { + count += req->tables.huff_bits[index][i]; + } + + if (rt_memcmp(req->tables.huff_bits[index], + jpu_default_huff_bits[index], JPU_HUFF_BITS_NUM) || + rt_memcmp(req->tables.huff_values[index], + jpu_default_huff_values[index], count)) + { + return RT_FALSE; + } + } + } + + return RT_TRUE; +} + +static void spacemit_jpu_build_decode_regs(const struct jpu_decode_request *req, + const struct spacemit_jpu_map *map, rt_uint32_t *reg) +{ + const struct jpu_frame_info *frame = &req->frame; + rt_uint32_t y_size = frame->y_stride * frame->aligned_height; + rt_uint32_t c_size = frame->c_stride * frame->c_height; + rt_uint32_t dc = req->dc_selector[0]; + rt_uint32_t ac = req->ac_selector[0]; + rt_uint32_t mcu_width; + rt_uint32_t mcu_height; + rt_uint32_t mcu_blocks; + rt_uint32_t bus_requests; + rt_uint32_t comp0; + rt_uint32_t stream_end = (rt_uint32_t)map->stream_iova + req->stream_size; + + switch (frame->format) + { + case JPU_FORMAT_420: + mcu_width = 16; + mcu_height = 16; + mcu_blocks = 6; + bus_requests = 2; + break; + case JPU_FORMAT_422: + mcu_width = 16; + mcu_height = 8; + mcu_blocks = 4; + bus_requests = 3; + break; + case JPU_FORMAT_440: + mcu_width = 8; + mcu_height = 16; + mcu_blocks = 4; + bus_requests = 8; + break; + case JPU_FORMAT_444: + mcu_width = 8; + mcu_height = 8; + mcu_blocks = 3; + bus_requests = 4; + break; + default: + mcu_width = 8; + mcu_height = 8; + mcu_blocks = 1; + bus_requests = 4; + break; + } + + if (req->components == 3) + { + dc = (dc << 1) | req->dc_selector[1]; + dc = (dc << 1) | req->dc_selector[2]; + ac = (ac << 1) | req->ac_selector[1]; + ac = (ac << 1) | req->ac_selector[2]; + } + else + { + dc <<= 2; + ac <<= 2; + } + + comp0 = ((mcu_width >> 3) << 2) | (mcu_height >> 3); + reg[MJPEG_PIC_START_REG / 4] = 1; + reg[MJPEG_PIC_CTRL_REG / 4] = (ac << 10) | (dc << 7); + if (!spacemit_jpu_uses_default_huffman(req)) + { + reg[MJPEG_PIC_CTRL_REG / 4] |= RT_BIT(6); + } + reg[MJPEG_PIC_SIZE_REG / 4] = ((rt_uint32_t)frame->aligned_width << 16) | + frame->aligned_height; + reg[MJPEG_MCU_INFO_REG / 4] = (mcu_blocks << 16) | + ((rt_uint32_t)req->components << 12) | (comp0 << 8) | + ((req->components == 3 ? 5U : 0U) << 4) | + (req->components == 3 ? 5U : 0U); + reg[MJPEG_OP_INFO_REG / 4] = bus_requests; + reg[MJPEG_DPB_BASE00_REG / 4] = (rt_uint32_t)map->frame_iova; + reg[MJPEG_DPB_BASE01_REG / 4] = (rt_uint32_t)map->frame_iova + y_size; + reg[MJPEG_DPB_BASE02_REG / 4] = (rt_uint32_t)map->frame_iova + y_size + c_size; + reg[MJPEG_DPB_YSTRIDE_REG / 4] = frame->y_stride; + reg[MJPEG_DPB_CSTRIDE_REG / 4] = frame->c_stride; + reg[MJPEG_RST_INTVAL_REG / 4] = req->restart_interval; + reg[MJPEG_INTR_MASK_REG / 4] = + (~(RT_BIT(JPU_INT_DONE) | RT_BIT(JPU_INT_ERROR) | + RT_BIT(JPU_INT_BIT_BUF_EMPTY))) & 0x3ff; + reg[MJPEG_BBC_WR_PTR_REG / 4] = stream_end; + reg[MJPEG_BBC_END_ADDR_REG / 4] = JPU_ALIGN(stream_end, JPU_BBC_PAGE_SIZE); + reg[MJPEG_BBC_RD_PTR_REG / 4] = (rt_uint32_t)map->stream_iova; + reg[MJPEG_BBC_BAS_ADDR_REG / 4] = (rt_uint32_t)map->stream_iova; + reg[MJPEG_BBC_STRM_CTRL_REG / 4] = RT_BIT(31) | + RT_DIV_ROUND_UP(req->stream_size, JPU_BBC_PAGE_SIZE); +} + +static void spacemit_jpu_make_huffman_table(const struct jpu_dec_tables *tables, + rt_uint16_t min[JPU_HUFF_TABLE_NUM][JPU_HUFF_BITS_NUM], + rt_uint16_t max[JPU_HUFF_TABLE_NUM][JPU_HUFF_BITS_NUM], + rt_uint8_t ptr[JPU_HUFF_TABLE_NUM][JPU_HUFF_BITS_NUM]) +{ + int table, length; + + for (table = 0; table < JPU_HUFF_TABLE_NUM; ++table) + { + rt_uint32_t code = 0; + rt_uint32_t value_index = 0; + rt_bool_t have_code = RT_FALSE; + + for (length = 0; length < JPU_HUFF_BITS_NUM; ++length) + { + rt_uint32_t count = tables->huff_bits[table][length]; + + if (count) + { + ptr[table][length] = value_index; + min[table][length] = code; + max[table][length] = code + count - 1; + value_index += count; + code = (max[table][length] + 1) << 1; + have_code = RT_TRUE; + } + else + { + ptr[table][length] = 0xff; + min[table][length] = 0xffff; + max[table][length] = 0xffff; + if (have_code) + { + code <<= 1; + } + } + } + } +} + +static rt_err_t spacemit_jpu_load_huffman(struct spacemit_jpu *jpu, + const struct jpu_dec_tables *tables) +{ + static const rt_uint8_t order[JPU_HUFF_TABLE_NUM] = { 0, 2, 1, 3 }; + rt_uint16_t min[JPU_HUFF_TABLE_NUM][JPU_HUFF_BITS_NUM]; + rt_uint16_t max[JPU_HUFF_TABLE_NUM][JPU_HUFF_BITS_NUM]; + rt_uint8_t ptr[JPU_HUFF_TABLE_NUM][JPU_HUFF_BITS_NUM]; + int count[JPU_HUFF_TABLE_NUM] = { 0 }; + int table, i; + + for (table = 0; table < JPU_HUFF_TABLE_NUM; ++table) + { + for (i = 0; i < JPU_HUFF_BITS_NUM; ++i) + { + count[table] += tables->huff_bits[table][i]; + } + + if (count[table] <= 0 || + count[table] > ((table & 1) ? JPU_HUFF_VALUES_NUM : 12)) + { + return -RT_EINVAL; + } + } + + spacemit_jpu_make_huffman_table(tables, min, max, ptr); + + spacemit_jpu_write(jpu, MJPEG_HUFF_CTRL_REG, 0x003); + for (table = 0; table < JPU_HUFF_TABLE_NUM; ++table) + { + int index = order[table]; + + for (i = 0; i < JPU_HUFF_BITS_NUM; ++i) + { + spacemit_jpu_write(jpu, MJPEG_HUFF_DATA_REG, + (rt_uint32_t)(rt_int32_t)(rt_int16_t)min[index][i]); + } + } + + spacemit_jpu_write(jpu, MJPEG_HUFF_CTRL_REG, 0x403); + spacemit_jpu_write(jpu, MJPEG_HUFF_ADDR_REG, 0x440); + for (table = 0; table < JPU_HUFF_TABLE_NUM; ++table) + { + int index = order[table]; + + for (i = 0; i < JPU_HUFF_BITS_NUM; ++i) + { + spacemit_jpu_write(jpu, MJPEG_HUFF_DATA_REG, + (rt_uint32_t)(rt_int32_t)(rt_int16_t)max[index][i]); + } + } + + spacemit_jpu_write(jpu, MJPEG_HUFF_CTRL_REG, 0x803); + spacemit_jpu_write(jpu, MJPEG_HUFF_ADDR_REG, 0x880); + for (table = 0; table < JPU_HUFF_TABLE_NUM; ++table) + { + int index = order[table]; + + for (i = 0; i < JPU_HUFF_BITS_NUM; ++i) + { + spacemit_jpu_write(jpu, MJPEG_HUFF_DATA_REG, + (rt_uint32_t)(rt_int32_t)(rt_int8_t)ptr[index][i]); + } + } + + spacemit_jpu_write(jpu, MJPEG_HUFF_CTRL_REG, 0xc03); + for (table = 0; table < JPU_HUFF_TABLE_NUM; ++table) + { + int index = order[table]; + int slots = (index & 1) ? JPU_HUFF_VALUES_NUM : 12; + + for (i = 0; i < count[index]; ++i) + { + spacemit_jpu_write(jpu, MJPEG_HUFF_DATA_REG, + (rt_uint32_t)(rt_int32_t)(rt_int8_t)tables->huff_values[index][i]); + } + for (; i < slots; ++i) + { + spacemit_jpu_write(jpu, MJPEG_HUFF_DATA_REG, 0xffffffff); + } + } + spacemit_jpu_write(jpu, MJPEG_HUFF_CTRL_REG, 0); + + return RT_EOK; +} + +static void spacemit_jpu_load_quant(struct spacemit_jpu *jpu, + const struct jpu_dec_tables *tables) +{ + static const rt_uint32_t control[JPU_QUANT_COMPONENT_NUM] = { 0x03, 0x43, 0x83 }; + int component, i; + + for (component = 0; component < JPU_QUANT_COMPONENT_NUM; ++component) + { + spacemit_jpu_write(jpu, MJPEG_QMAT_CTRL_REG, control[component]); + for (i = 0; i < JPU_QUANT_VALUES_NUM; ++i) + { + spacemit_jpu_write(jpu, MJPEG_QMAT_DATA_REG, + tables->quant[component][i]); + } + spacemit_jpu_write(jpu, MJPEG_QMAT_CTRL_REG, 0); + } +} + +static rt_err_t spacemit_jpu_wait_bbc(struct spacemit_jpu *jpu) +{ + int timeout = JPU_BBC_TIMEOUT_US; + + while (spacemit_jpu_read(jpu, MJPEG_BBC_BUSY_REG) & 1) + { + if (--timeout == 0) + { + LOG_E("JPU BBC preload timeout"); + return -RT_ETIMEOUT; + } + rt_hw_us_delay(1); + } + + return RT_EOK; +} + +static rt_err_t spacemit_jpu_prepare_stream(struct spacemit_jpu *jpu, + rt_uint32_t stream_base, rt_uint32_t entropy_offset) +{ + rt_uint32_t page = entropy_offset >> 8; + rt_uint32_t word = (entropy_offset & 0xf0) >> 2; + rt_uint32_t bit = (entropy_offset & 0xf) << 3; + int i; + + if (page & 1) + { + word += 64; + } + if (word & 1) + { + --word; + } + + for (i = 0; i < 2; ++i) + { + rt_uint32_t current = page + i; + + spacemit_jpu_write(jpu, MJPEG_BBC_CUR_POS_REG, current); + spacemit_jpu_write(jpu, MJPEG_BBC_EXT_ADDR_REG, stream_base + (current << 8)); + spacemit_jpu_write(jpu, MJPEG_BBC_INT_ADDR_REG, (current & 1) << 6); + spacemit_jpu_write(jpu, MJPEG_BBC_DATA_CNT_REG, 64); + spacemit_jpu_write(jpu, MJPEG_BBC_COMMAND_REG, 0); + if (spacemit_jpu_wait_bbc(jpu) != RT_EOK) + { + return -RT_ETIMEOUT; + } + } + + spacemit_jpu_write(jpu, MJPEG_BBC_CUR_POS_REG, page + 2); + spacemit_jpu_write(jpu, MJPEG_BBC_CTRL_REG, 1); + spacemit_jpu_write(jpu, MJPEG_GBU_WD_PTR_REG, word); + spacemit_jpu_write(jpu, MJPEG_GBU_BBSR_REG, 0); + spacemit_jpu_write(jpu, MJPEG_GBU_BBER_REG, 127); + spacemit_jpu_write(jpu, MJPEG_GBU_BBIR_REG, (page & 1) ? 0 : 64); + spacemit_jpu_write(jpu, MJPEG_GBU_BBHR_REG, (page & 1) ? 0 : 64); + spacemit_jpu_write(jpu, MJPEG_GBU_CTRL_REG, 4); + spacemit_jpu_write(jpu, MJPEG_GBU_FF_RPTR_REG, bit); + + return RT_EOK; +} + +static void spacemit_jpu_dump_timeout(struct spacemit_jpu *jpu) +{ + LOG_E("core: start=%08x status=%08x errmb=%08x cycle=%08x", + spacemit_jpu_read(jpu, MJPEG_PIC_START_REG), + spacemit_jpu_read(jpu, MJPEG_PIC_STATUS_REG), + spacemit_jpu_read(jpu, MJPEG_PIC_ERRMB_REG), + spacemit_jpu_read(jpu, MJPEG_CYCLE_INFO_REG)); + LOG_E("BBC: busy=%08x pos=%08x rd=%08x wr=%08x end=%08x ctrl=%08x", + spacemit_jpu_read(jpu, MJPEG_BBC_BUSY_REG), + spacemit_jpu_read(jpu, MJPEG_BBC_CUR_POS_REG), + spacemit_jpu_read(jpu, MJPEG_BBC_RD_PTR_REG), + spacemit_jpu_read(jpu, MJPEG_BBC_WR_PTR_REG), + spacemit_jpu_read(jpu, MJPEG_BBC_END_ADDR_REG), + spacemit_jpu_read(jpu, MJPEG_BBC_STRM_CTRL_REG)); + LOG_E("GBU: ctrl=%08x word=%08x bit=%08x count=%08x MMU=%08x/%08x/%08x", + spacemit_jpu_read(jpu, MJPEG_GBU_CTRL_REG), + spacemit_jpu_read(jpu, MJPEG_GBU_WD_PTR_REG), + spacemit_jpu_read(jpu, MJPEG_GBU_FF_RPTR_REG), + spacemit_jpu_read(jpu, MJPEG_GBU_TT_CNT_REG), + spacemit_jpu_read(jpu, MJPEG_MMU_IRQ_STATUS), + spacemit_jpu_read(jpu, MJPEG_MMU_TBU_STATUS_BASE), + spacemit_jpu_read(jpu, MJPEG_MMU_TBU_STATUS_BASE + MJPEG_MMU_TBUx_STEP)); +} + +#if DBG_LVL >= DBG_LOG +static void spacemit_jpu_dump_config(struct spacemit_jpu *jpu, + const struct spacemit_jpu_map *map) +{ + LOG_D("DMA: stream=%08x->%08x/%u frame=%08x->%08x/%u MMU=%u", + (rt_uint32_t)map->stream_phys, (rt_uint32_t)map->stream_iova, + (unsigned int)map->stream_size, (rt_uint32_t)map->frame_phys, + (rt_uint32_t)map->frame_iova, (unsigned int)map->frame_size, + (unsigned int)jpu->mmu_enable); + LOG_D("core: mask=%08x ctrl=%08x pic=%08x mcu=%08x op=%08x dpbcfg=%08x", + spacemit_jpu_read(jpu, MJPEG_INTR_MASK_REG), + spacemit_jpu_read(jpu, MJPEG_PIC_CTRL_REG), + spacemit_jpu_read(jpu, MJPEG_PIC_SIZE_REG), + spacemit_jpu_read(jpu, MJPEG_MCU_INFO_REG), + spacemit_jpu_read(jpu, MJPEG_OP_INFO_REG), + spacemit_jpu_read(jpu, MJPEG_DPB_CONFIG_REG)); + LOG_D("DPB: y=%08x cb=%08x cr=%08x stride=%08x/%08x", + spacemit_jpu_read(jpu, MJPEG_DPB_BASE00_REG), + spacemit_jpu_read(jpu, MJPEG_DPB_BASE01_REG), + spacemit_jpu_read(jpu, MJPEG_DPB_BASE02_REG), + spacemit_jpu_read(jpu, MJPEG_DPB_YSTRIDE_REG), + spacemit_jpu_read(jpu, MJPEG_DPB_CSTRIDE_REG)); + LOG_D("BBC: base=%08x rd=%08x wr=%08x end=%08x pos=%08x ctrl=%08x", + spacemit_jpu_read(jpu, MJPEG_BBC_BAS_ADDR_REG), + spacemit_jpu_read(jpu, MJPEG_BBC_RD_PTR_REG), + spacemit_jpu_read(jpu, MJPEG_BBC_WR_PTR_REG), + spacemit_jpu_read(jpu, MJPEG_BBC_END_ADDR_REG), + spacemit_jpu_read(jpu, MJPEG_BBC_CUR_POS_REG), + spacemit_jpu_read(jpu, MJPEG_BBC_STRM_CTRL_REG)); + LOG_D("GBU: word=%08x bit=%08x range=%08x/%08x/%08x/%08x ctrl=%08x", + spacemit_jpu_read(jpu, MJPEG_GBU_WD_PTR_REG), + spacemit_jpu_read(jpu, MJPEG_GBU_FF_RPTR_REG), + spacemit_jpu_read(jpu, MJPEG_GBU_BBSR_REG), + spacemit_jpu_read(jpu, MJPEG_GBU_BBER_REG), + spacemit_jpu_read(jpu, MJPEG_GBU_BBIR_REG), + spacemit_jpu_read(jpu, MJPEG_GBU_BBHR_REG), + spacemit_jpu_read(jpu, MJPEG_GBU_CTRL_REG)); +} +#endif + +static rt_err_t spacemit_jpu_submit(struct spacemit_jpu *jpu, + struct jpu_decode_request *req) +{ + struct spacemit_jpu_map map; + rt_uint32_t reg[JPU_DECODE_REG_NUM] = { 0 }; + rt_err_t err; + + if ((err = spacemit_jpu_validate_decode(req)) != RT_EOK) + { + return err; + } + + if (spacemit_jpu_read(jpu, MJPEG_PIC_START_REG) != 0) + { + LOG_E("JPU busy"); + return -RT_EBUSY; + } + + req->irq_status = 0; + req->picture_status = 0; + req->error_mcu = 0; + req->cycles = 0; + + if ((err = spacemit_jpu_sw_reset(jpu)) != RT_EOK) + { + return err; + } + rt_completion_init(&jpu->completion); + jpu->error = RT_EOK; + jpu->irq_reason = 0; + + map.stream_phys = req->stream_phys; + map.stream_size = req->stream_capacity; + map.frame_phys = req->frame_phys; + map.frame_size = req->frame_capacity; + if ((err = spacemit_jpu_mmu_map(jpu, &map)) != RT_EOK) + { + LOG_E("failed to map decode buffers: %d", err); + goto _fail; + } + + spacemit_jpu_build_decode_regs(req, &map, reg); + + LOG_D("config: pic=%08x mcu=%08x ctrl=%08x entropy=%u stream=%u", + reg[MJPEG_PIC_SIZE_REG / sizeof(rt_uint32_t)], + reg[MJPEG_MCU_INFO_REG / sizeof(rt_uint32_t)], + reg[MJPEG_PIC_CTRL_REG / sizeof(rt_uint32_t)], + req->entropy_offset, req->stream_size); + + /* Keep this sequence aligned with JPU_DecSetRdPtrEx() and + * JPU_DecStartOneFrame() from the vendor library. */ + spacemit_jpu_write(jpu, MJPEG_BBC_RD_PTR_REG, + reg[MJPEG_BBC_RD_PTR_REG / sizeof(rt_uint32_t)]); + spacemit_jpu_write(jpu, MJPEG_INTR_MASK_REG, + reg[MJPEG_INTR_MASK_REG / sizeof(rt_uint32_t)]); + spacemit_jpu_write(jpu, MJPEG_BBC_WR_PTR_REG, + reg[MJPEG_BBC_WR_PTR_REG / sizeof(rt_uint32_t)]); + spacemit_jpu_write(jpu, MJPEG_BBC_END_ADDR_REG, + reg[MJPEG_BBC_END_ADDR_REG / sizeof(rt_uint32_t)]); + spacemit_jpu_write(jpu, MJPEG_BBC_BAS_ADDR_REG, + reg[MJPEG_BBC_BAS_ADDR_REG / sizeof(rt_uint32_t)]); + spacemit_jpu_write(jpu, MJPEG_GBU_TT_CNT_REG, 0); + spacemit_jpu_write(jpu, MJPEG_GBU_TT_CNT_REG + sizeof(rt_uint32_t), 0); + spacemit_jpu_write(jpu, MJPEG_PIC_ERRMB_REG, 0); + spacemit_jpu_write(jpu, MJPEG_PIC_CTRL_REG, + reg[MJPEG_PIC_CTRL_REG / sizeof(rt_uint32_t)]); + spacemit_jpu_write(jpu, MJPEG_PIC_SIZE_REG, + reg[MJPEG_PIC_SIZE_REG / sizeof(rt_uint32_t)]); + spacemit_jpu_write(jpu, MJPEG_OP_INFO_REG, + reg[MJPEG_OP_INFO_REG / sizeof(rt_uint32_t)]); + spacemit_jpu_write(jpu, MJPEG_MCU_INFO_REG, + reg[MJPEG_MCU_INFO_REG / sizeof(rt_uint32_t)]); + spacemit_jpu_write(jpu, MJPEG_DPB_CONFIG_REG, 0); + spacemit_jpu_write(jpu, MJPEG_RST_INTVAL_REG, + reg[MJPEG_RST_INTVAL_REG / sizeof(rt_uint32_t)]); + spacemit_jpu_write(jpu, MJPEG_SCL_INFO_REG, 0); + + if ((reg[MJPEG_PIC_CTRL_REG / sizeof(rt_uint32_t)] & RT_BIT(6)) && + (err = spacemit_jpu_load_huffman(jpu, &req->tables)) != RT_EOK) + { + LOG_E("invalid Huffman tables"); + goto _fail; + } + + spacemit_jpu_load_quant(jpu, &req->tables); + if ((err = spacemit_jpu_prepare_stream(jpu, + map.stream_iova, req->entropy_offset)) != RT_EOK) + { + goto _fail; + } + if (jpu->error != RT_EOK) + { + err = jpu->error; + goto _fail; + } + + spacemit_jpu_write(jpu, MJPEG_BBC_STRM_CTRL_REG, + reg[MJPEG_BBC_STRM_CTRL_REG / sizeof(rt_uint32_t)]); + spacemit_jpu_write(jpu, MJPEG_RST_INDEX_REG, 0); + spacemit_jpu_write(jpu, MJPEG_RST_COUNT_REG, 0); + spacemit_jpu_write(jpu, MJPEG_DPCM_DIFF_Y_REG, 0); + spacemit_jpu_write(jpu, MJPEG_DPCM_DIFF_CB_REG, 0); + spacemit_jpu_write(jpu, MJPEG_DPCM_DIFF_CR_REG, 0); + spacemit_jpu_write(jpu, MJPEG_GBU_FF_RPTR_REG, + (req->entropy_offset & 0xf) << 3); + spacemit_jpu_write(jpu, MJPEG_GBU_CTRL_REG, 3); + + spacemit_jpu_write(jpu, MJPEG_ROT_INFO_REG, 0); + spacemit_jpu_write(jpu, MJPEG_DPB_BASE00_REG, + reg[MJPEG_DPB_BASE00_REG / sizeof(rt_uint32_t)]); + spacemit_jpu_write(jpu, MJPEG_DPB_BASE01_REG, + reg[MJPEG_DPB_BASE01_REG / sizeof(rt_uint32_t)]); + spacemit_jpu_write(jpu, MJPEG_DPB_BASE02_REG, + reg[MJPEG_DPB_BASE02_REG / sizeof(rt_uint32_t)]); + spacemit_jpu_write(jpu, MJPEG_DPB_YSTRIDE_REG, + reg[MJPEG_DPB_YSTRIDE_REG / sizeof(rt_uint32_t)]); + spacemit_jpu_write(jpu, MJPEG_DPB_CSTRIDE_REG, + reg[MJPEG_DPB_CSTRIDE_REG / sizeof(rt_uint32_t)]); + spacemit_jpu_write(jpu, MJPEG_CLP_INFO_REG, 0); + + rt_hw_dsb(); +#if DBG_LVL >= DBG_LOG + spacemit_jpu_dump_config(jpu, &map); +#endif + + spacemit_jpu_write(jpu, MJPEG_PIC_START_REG, reg[MJPEG_PIC_START_REG / 4]); + + if (rt_completion_wait(&jpu->completion, + rt_tick_from_millisecond(JPU_TIMEOUT_MS)) != RT_EOK) + { + LOG_E("JPU timeout"); + spacemit_jpu_dump_timeout(jpu); + err = -RT_ETIMEOUT; + goto _fail; + } + + req->irq_status = jpu->irq_reason; + req->picture_status = spacemit_jpu_read(jpu, MJPEG_PIC_STATUS_REG); + req->error_mcu = spacemit_jpu_read(jpu, MJPEG_PIC_ERRMB_REG); + req->cycles = spacemit_jpu_read(jpu, MJPEG_CYCLE_INFO_REG); + + spacemit_jpu_disable_mmu_hw(jpu); + + if (jpu->error != RT_EOK) + { + spacemit_jpu_hard_reset(jpu); + } + + return jpu->error; + +_fail: + req->irq_status = jpu->irq_reason; + req->picture_status = spacemit_jpu_read(jpu, MJPEG_PIC_STATUS_REG); + req->error_mcu = spacemit_jpu_read(jpu, MJPEG_PIC_ERRMB_REG); + req->cycles = spacemit_jpu_read(jpu, MJPEG_CYCLE_INFO_REG); + spacemit_jpu_hard_reset(jpu); + spacemit_jpu_disable_mmu_hw(jpu); + return err; +} + +static rt_err_t spacemit_jpu_control(rt_device_t dev, int cmd, void *args) +{ + rt_err_t err = RT_EOK; + struct spacemit_jpu *jpu = raw_to_spacemit_jpu(dev); + + rt_mutex_take(&jpu->lock, RT_WAITING_FOREVER); + + switch (cmd) + { + case JPU_DECODE: + { + struct jpu_decode_request *req = args; + + if (!req) + { + err = -RT_EINVAL; + break; + } + + err = spacemit_jpu_submit(jpu, req); + break; + } + case JPU_QUERY_FRAME: + { + struct jpu_frame_info *frame = args; + + if (!frame) + { + err = -RT_EINVAL; + break; + } + + err = spacemit_jpu_query_frame(frame); + break; + } + case JPU_ALLOC_BUFFER: + { + struct jpu_buffer *buf = args; + + if (!buf) + { + err = -RT_EINVAL; + break; + } + + err = spacemit_jpu_buffer_alloc(jpu, buf); + break; + } + case JPU_FREE_BUFFER: + { + struct jpu_buffer *buf = args; + + if (!buf) + { + err = -RT_EINVAL; + break; + } + + err = spacemit_jpu_buffer_free(jpu, buf); + break; + } + case JPU_RESET: + spacemit_jpu_hard_reset(jpu); + spacemit_jpu_disable_mmu_hw(jpu); + break; + case JPU_GET_MMU_VERSION: + { + rt_uint32_t *version = args; + + if (!version) + { + err = -RT_EINVAL; + break; + } + + *version = spacemit_jpu_read(jpu, MJPEG_MMU_VERSION); + break; + } + default: + err = -RT_ENOSYS; + break; + } + + rt_mutex_release(&jpu->lock); + + return err; +} + +#ifdef RT_USING_DEVICE_OPS +static const struct rt_device_ops spacemit_jpu_ops = +{ + .control = spacemit_jpu_control, +}; +#endif + +static void spacemit_jpu_isr(int irqno, void *param) +{ + rt_uint32_t int_reason; + rt_uint32_t mmu_irq_status; + rt_bool_t completed = RT_FALSE; + struct spacemit_jpu *jpu = param; + + int_reason = spacemit_jpu_read(jpu, MJPEG_PIC_STATUS_REG); + if (int_reason != 0) + { + if (int_reason & RT_BIT(JPU_INT_DONE)) + { + spacemit_jpu_write(jpu, MJPEG_BBC_FLUSH_CMD_REG, 0); + } + + spacemit_jpu_write(jpu, MJPEG_PIC_STATUS_REG, int_reason); + } + + mmu_irq_status = spacemit_jpu_read(jpu, MJPEG_MMU_IRQ_STATUS); + if (mmu_irq_status != 0) + { + LOG_E("JPU MMU fault: status 0x%08x", mmu_irq_status); + + if (mmu_irq_status & 0xFF) + { + spacemit_jpu_set_bits(jpu, MJPEG_MMU_ERROR_CLEAR, RT_BIT(1)); + } + + spacemit_jpu_write(jpu, MJPEG_MMU_IRQ_STATUS, mmu_irq_status); + jpu->error = -RT_EIO; + completed = RT_TRUE; + } + + if (int_reason != 0) + { + jpu->irq_reason |= int_reason; + + if (int_reason & JPU_INT_FATAL_MASK) + { + LOG_E("JPU error, status = 0x%08x", int_reason); + jpu->error = -RT_EIO; + } + + if (int_reason & (RT_BIT(JPU_INT_DONE) | JPU_INT_FATAL_MASK)) + { + completed = RT_TRUE; + } + } + + if (completed) + { + rt_completion_done(&jpu->completion); + } +} + +static struct rt_reset_control *spacemit_jpu_get_reset(struct rt_device *dev, const char *name) +{ + struct rt_reset_control *rstc = rt_reset_control_get_by_name(dev, name); + + if (rt_is_err(rstc)) + { + LOG_W("no %s reset, err = %d", name, rt_ptr_err(rstc)); + return RT_NULL; + } + + return rstc; +} + +static void spacemit_jpu_free(struct spacemit_jpu *jpu) +{ + void *ttb_va = RT_NULL; + rt_ubase_t ttb_pa = 0; + + if (jpu->tbu[0].ttb_va) + { + ttb_va = jpu->tbu[0].ttb_va; + ttb_pa = jpu->tbu[0].ttb_pa; + } + + if (ttb_va && jpu->dev) + { + rt_dma_free_coherent(jpu->dev, MAX_SIZE_PER_TTB * TBU_INSTANCES_NUM, + ttb_va, ttb_pa); + } + + if (jpu->regs) + { + rt_iounmap(jpu->regs); + } + + spacemit_jpu_clk_disable(jpu); + + if (!rt_is_err_or_null(jpu->cclk)) + { + rt_clk_put(jpu->cclk); + } + if (!rt_is_err_or_null(jpu->aclk)) + { + rt_clk_put(jpu->aclk); + } + if (!rt_is_err_or_null(jpu->iclk)) + { + rt_clk_put(jpu->iclk); + } + + if (!rt_is_err_or_null(jpu->jpg_reset)) + { + rt_reset_control_put(jpu->jpg_reset); + } + if (!rt_is_err_or_null(jpu->lcd_mclk_reset)) + { + rt_reset_control_put(jpu->lcd_mclk_reset); + } + if (!rt_is_err_or_null(jpu->isp_ci_reset)) + { + rt_reset_control_put(jpu->isp_ci_reset); + } + if (!rt_is_err_or_null(jpu->freset)) + { + rt_reset_control_put(jpu->freset); + } + if (!rt_is_err_or_null(jpu->sreset)) + { + rt_reset_control_put(jpu->sreset); + } + + rt_free(jpu); +} + +static rt_err_t spacemit_jpu_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + rt_uint32_t chip_id = 0; + const char *dev_name; + struct rt_device *dev = &pdev->parent; + struct spacemit_jpu *jpu = rt_calloc(1, sizeof(*jpu)); + void *ttb_va = RT_NULL; + rt_ubase_t ttb_pa = 0; + int i; + + if (!jpu) + { + return -RT_ENOMEM; + } + + jpu->dev = dev; + + jpu->regs = rt_dm_dev_iomap(dev, 0); + if (!jpu->regs) + { + err = -RT_EIO; + goto _fail; + } + + if (!rt_dm_dev_prop_read_u32(dev, "page-size", &jpu->page_size)) + { + jpu->page_size *= 1024; + } + else + { + jpu->page_size = 4096; + } + + jpu->cclk = rt_clk_get_by_name(dev, "cclk"); + if (rt_is_err(jpu->cclk)) + { + err = rt_ptr_err(jpu->cclk); + goto _fail; + } + + jpu->aclk = rt_clk_get_by_name(dev, "aclk"); + if (rt_is_err(jpu->aclk)) + { + err = rt_ptr_err(jpu->aclk); + goto _fail; + } + + jpu->iclk = rt_clk_get_by_name(dev, "iclk"); + if (rt_is_err(jpu->iclk)) + { + err = rt_ptr_err(jpu->iclk); + goto _fail; + } + + if ((err = spacemit_jpu_clk_enable(jpu)) != RT_EOK) + { + goto _fail; + } + + jpu->jpg_reset = spacemit_jpu_get_reset(dev, "jpg_reset"); + jpu->lcd_mclk_reset = spacemit_jpu_get_reset(dev, "lcd_mclk_reset"); + jpu->isp_ci_reset = spacemit_jpu_get_reset(dev, "isp_ci_reset"); + jpu->freset = spacemit_jpu_get_reset(dev, "freset"); + jpu->sreset = spacemit_jpu_get_reset(dev, "sreset"); + spacemit_jpu_reset_deassert_all(jpu); + + jpu->irq = rt_dm_dev_get_irq(dev, 0); + if (jpu->irq < 0) + { + err = jpu->irq; + goto _fail; + } + + ttb_va = rt_dma_alloc_coherent(dev, MAX_SIZE_PER_TTB * TBU_INSTANCES_NUM, &ttb_pa); + if (!ttb_va) + { + LOG_E("No memory for TBU page tables"); + err = -RT_ENOMEM; + goto _fail; + } + rt_memset(ttb_va, 0, MAX_SIZE_PER_TTB * TBU_INSTANCES_NUM); + + for (i = 0; i < TBU_INSTANCES_NUM; i++) + { + jpu->tbu[i].ttb_va = (rt_uint32_t *)((rt_uint8_t *)ttb_va + i * MAX_SIZE_PER_TTB); + jpu->tbu[i].ttb_pa = ttb_pa + i * MAX_SIZE_PER_TTB; + } + + jpu->va_base = JPU_TBU_BASE_VA; + jpu->time_out_cycs = DEFAULT_TIMEOUT_CYCS; + rt_spin_lock_init(&jpu->hw_lock); + + if (!rt_dm_dev_prop_read_u32(dev, "jpu,chip-id", &chip_id)) + { + rt_dm_dev_set_name(&jpu->parent, "jpu%u", chip_id); + } + else + { + rt_dm_dev_set_name_auto(&jpu->parent, "jpu"); + } + dev_name = rt_dm_dev_get_name(&jpu->parent); + + dev->user_data = jpu; + + jpu->parent.type = RT_Device_Class_Char; +#ifdef RT_USING_DEVICE_OPS + jpu->parent.ops = &spacemit_jpu_ops; +#else + jpu->parent.control = spacemit_jpu_control; +#endif + + if ((err = rt_device_register(&jpu->parent, dev_name, RT_DEVICE_FLAG_DEACTIVATE))) + { + goto _fail; + } + + rt_mutex_init(&jpu->lock, dev_name, RT_IPC_FLAG_PRIO); + rt_completion_init(&jpu->completion); + + rt_hw_interrupt_install(jpu->irq, spacemit_jpu_isr, jpu, "jpu"); + rt_hw_interrupt_umask(jpu->irq); + + LOG_I("Chip Media JPU probed, MMU version 0x%08x", + spacemit_jpu_read(jpu, MJPEG_MMU_VERSION)); + + return RT_EOK; + +_fail: + spacemit_jpu_free(jpu); + + return err; +} + +static rt_err_t spacemit_jpu_remove(struct rt_platform_device *pdev) +{ + struct spacemit_jpu *jpu = pdev->parent.user_data; + + rt_hw_interrupt_mask(jpu->irq); + rt_pic_detach_irq(jpu->irq, jpu); + + rt_device_unregister(&jpu->parent); + + spacemit_jpu_free(jpu); + + return RT_EOK; +} + +static const struct rt_ofw_node_id spacemit_jpu_ofw_ids[] = +{ + { .compatible = "chip-media, jpu" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_jpu_driver = +{ + .name = "spacemit-jpu", + .ids = spacemit_jpu_ofw_ids, + + .probe = spacemit_jpu_probe, + .remove = spacemit_jpu_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(spacemit_jpu_driver); diff --git a/bsp/spacemit/dm/soc/k1x-rproc.c b/bsp/spacemit/dm/soc/k1x-rproc.c new file mode 100644 index 000000000000..bdf60330c7a9 --- /dev/null +++ b/bsp/spacemit/dm/soc/k1x-rproc.c @@ -0,0 +1,1557 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define DBG_TAG "soc.k1x-rproc" +#define DBG_LVL DBG_INFO +#include + +#include +#include + +#define K1X_MBOX_VQ0_ID 0 +#define K1X_MBOX_VQ1_ID 1 + +#define K1X_RPMSG_VRING0_REGION 2 +#define K1X_RPMSG_VRING1_REGION 3 +#define K1X_RPMSG_BUFFER_REGION 4 +#define K1X_RPMSG_RSC_REGION 5 + +#define K1X_RPMSG_VRING0_NAME "vdev0vring0" +#define K1X_RPMSG_VRING1_NAME "vdev0vring1" +#define K1X_RPMSG_BUFFER_NAME "vdev0buffer" +#define K1X_RPMSG_RSC_NAME "rsc_table" + +#define K1X_RPMSG_QUEUE_NUM 256 +#define K1X_RPMSG_BUFFER_SIZE 512 +#define K1X_RPMSG_MAX_MEMORY_REGIONS 16 +#define K1X_RPMSG_VRING0_NOTIFY_ID 0 +#define K1X_RPMSG_VRING1_NOTIFY_ID 1 +#define K1X_RPMSG_VIRTIO_VENDOR 0x53504d54U + +#define K1X_RSC_VDEV 3 +#define K1X_VIRTIO_ID_RPMSG 7 +#define K1X_VIRTIO_RPMSG_F_NS RT_BIT(0) + +#define FW_BOOT_ENTRY_REG_OFFSET 0x88 +#define FW_BOOTUP_REG_OFFSET 0x30 +#define FW_AON_PER_CLK_RST_CTL_REG 0x2c + +#define FW_DDR_REGMAP_BASE_REG_OFFSET 0xc0 + +static char *const mb_name[] = +{ + [K1X_MBOX_VQ0_ID] = "vq0", + [K1X_MBOX_VQ1_ID] = "vq1", +}; + +struct spacemit_rproc; + +struct spacemit_rproc_mbox +{ + struct rt_mbox_client parent; + + struct rt_mbox_chan *chan; + + int vq_id; + struct spacemit_rproc *rproc; +}; + +struct spacemit_rpmsg_region +{ + void *va; + rt_uint64_t pa; + rt_uint64_t size; + rt_uint32_t da; +}; + +struct spacemit_fw_rsc_vdev_vring +{ + rt_uint32_t da; + rt_uint32_t align; + rt_uint32_t num; + rt_uint32_t notifyid; + rt_uint32_t reserved; +}; + +struct spacemit_fw_rsc_vdev +{ + rt_uint32_t type; + rt_uint32_t id; + rt_uint32_t notifyid; + rt_uint32_t dfeatures; + rt_uint32_t gfeatures; + rt_uint32_t config_len; + rt_uint8_t status; + rt_uint8_t num_of_vrings; + rt_uint8_t reserved[2]; + struct spacemit_fw_rsc_vdev_vring vring[2]; +}; + +struct spacemit_resource_table +{ + rt_uint32_t version; + rt_uint32_t num; + rt_uint32_t reserved[2]; + rt_uint32_t offset[1]; +}; + +struct spacemit_rproc +{ + struct rt_device *dev; + + void *bootc_mem_base; + void *sysctrl_mem_base; + + struct rt_clk *core_clk; + struct rt_clk *apb_clk; + struct rt_reset_control *core_rstc; + + rt_uint32_t apb_clk_rate; + rt_uint32_t ddr_remap_base; + rt_uint32_t fw_entry_point; + char fw_name[32]; + struct spacemit_rproc_mbox mb[RT_ARRAY_SIZE(mb_name)]; + + struct spacemit_rpmsg_region vring_region[2]; + struct spacemit_rpmsg_region buffer_region; + struct spacemit_rpmsg_region rsc_region; + struct rt_virtio_device vdev; + struct rt_virtqueue *vqs[2]; + rt_uint8_t virtio_status; + rt_uint64_t virtio_features; + rt_uint32_t vring_notify[2]; + rt_uint32_t vring_align[2]; + rt_uint16_t vring_num[2]; + rt_bool_t virtio_registered; + struct rt_spinlock dma_lock; + rt_uint8_t *dma_slots; + rt_size_t dma_slot_count; + rt_uint32_t rsc_vdev_offset; + rt_bool_t rpmsg_ready; + rt_bool_t firmware_started; + rt_bool_t boot_requested; + rt_bool_t clocks_enabled; + rt_bool_t worker_stop; + rt_bool_t worker_started; + rt_bool_t rpmsg_sem_inited; + rt_bool_t rpmsg_mutex_inited; + struct rt_semaphore rpmsg_sem; + struct rt_mutex rpmsg_mutex; + rt_thread_t rpmsg_thread; + rt_uint32_t notify_count[RT_ARRAY_SIZE(mb_name)]; + rt_uint32_t mbox_count[RT_ARRAY_SIZE(mb_name)]; +}; + +static struct spacemit_rproc *spacemit_rproc_global; +static RT_DEFINE_SPINLOCK(spacemit_rpmsg_lock); + +static rt_err_t spacemit_rproc_boot(struct spacemit_rproc *rproc); +static rt_err_t spacemit_rproc_stop(struct spacemit_rproc *rproc); +static void spacemit_rpmsg_notify(struct spacemit_rproc *rproc, int vq_id); + +static struct spacemit_rproc *spacemit_virtio_to_rproc( + struct rt_virtio_device *vdev) +{ + return rt_container_of(vdev, struct spacemit_rproc, vdev); +} + +static struct spacemit_fw_rsc_vdev *spacemit_rproc_rsc_vdev( + struct spacemit_rproc *rproc) +{ + struct spacemit_resource_table *table; + + if (!rproc || !rproc->rsc_region.va || + rproc->rsc_vdev_offset + sizeof(struct spacemit_fw_rsc_vdev) > + rproc->rsc_region.size) + { + return RT_NULL; + } + + table = rproc->rsc_region.va; + + return (void *)((char *)table + rproc->rsc_vdev_offset); +} + +static rt_err_t spacemit_rproc_dma_sync_out_data(struct rt_device *dev, + void *data, rt_size_t size, rt_ubase_t *dma_handle, + rt_ubase_t flags) +{ + rt_ubase_t level; + rt_size_t slot = 0; + rt_bool_t found = RT_FALSE; + struct rt_virtio_device *vdev = + rt_container_of(dev, struct rt_virtio_device, parent); + struct spacemit_rproc *rproc = spacemit_virtio_to_rproc(vdev); + + if (!data || !dma_handle || !rproc->dma_slots || + !rproc->dma_slot_count || size > K1X_RPMSG_BUFFER_SIZE) + { + return -RT_EINVAL; + } + + level = rt_spin_lock_irqsave(&rproc->dma_lock); + for (slot = 0; slot < rproc->dma_slot_count; ++slot) + { + if (!rproc->dma_slots[slot]) + { + rproc->dma_slots[slot] = 1; + found = RT_TRUE; + break; + } + } + rt_spin_unlock_irqrestore(&rproc->dma_lock, level); + + if (!found) + { + return -RT_EFULL; + } + + rt_memset((char *)rproc->buffer_region.va + + slot * K1X_RPMSG_BUFFER_SIZE, 0, K1X_RPMSG_BUFFER_SIZE); + rt_memcpy((char *)rproc->buffer_region.va + + slot * K1X_RPMSG_BUFFER_SIZE, data, size); + rt_hw_wmb(); + + *dma_handle = rproc->buffer_region.da + + slot * K1X_RPMSG_BUFFER_SIZE; + + return RT_EOK; +} + +static rt_err_t spacemit_rproc_dma_sync_in_data(struct rt_device *dev, + void *out_data, rt_size_t size, rt_ubase_t dma_handle, + rt_ubase_t flags) +{ + rt_ubase_t level; + rt_uint64_t offset; + rt_size_t slot; + struct rt_virtio_device *vdev = + rt_container_of(dev, struct rt_virtio_device, parent); + struct spacemit_rproc *rproc = spacemit_virtio_to_rproc(vdev); + + if (!out_data || !rproc->dma_slots || + dma_handle < rproc->buffer_region.da) + { + return -RT_EINVAL; + } + + offset = dma_handle - rproc->buffer_region.da; + if (offset >= rproc->buffer_region.size || + offset % K1X_RPMSG_BUFFER_SIZE) + { + return -RT_EINVAL; + } + + slot = offset / K1X_RPMSG_BUFFER_SIZE; + if (slot >= rproc->dma_slot_count) + { + return -RT_EINVAL; + } + + rt_hw_rmb(); + rt_memcpy(out_data, (char *)rproc->buffer_region.va + offset, + rt_min_t(rt_size_t, size, K1X_RPMSG_BUFFER_SIZE)); + + level = rt_spin_lock_irqsave(&rproc->dma_lock); + rproc->dma_slots[slot] = 0; + rt_spin_unlock_irqrestore(&rproc->dma_lock, level); + + return RT_EOK; +} + +static const struct rt_dma_map_ops spacemit_rproc_dma_ops = +{ + .sync_out_data = spacemit_rproc_dma_sync_out_data, + .sync_in_data = spacemit_rproc_dma_sync_in_data, +}; + +static rt_err_t spacemit_rproc_virtio_get_status( + struct rt_virtio_device *vdev, rt_uint8_t *out_status) +{ + struct spacemit_rproc *rproc = spacemit_virtio_to_rproc(vdev); + + *out_status = rproc->virtio_status; + + return RT_EOK; +} + +static rt_err_t spacemit_rproc_virtio_set_status( + struct rt_virtio_device *vdev, rt_uint8_t status) +{ + struct spacemit_fw_rsc_vdev *rsc_vdev; + struct spacemit_rproc *rproc = spacemit_virtio_to_rproc(vdev); + + rproc->virtio_status = status; + rsc_vdev = spacemit_rproc_rsc_vdev(rproc); + if (rsc_vdev) + { + rsc_vdev->status = status; + rt_hw_wmb(); + } + + return RT_EOK; +} + +static rt_err_t spacemit_rproc_virtio_get_features( + struct rt_virtio_device *vdev, rt_uint64_t *out_features) +{ + struct spacemit_rproc *rproc = spacemit_virtio_to_rproc(vdev); + + *out_features = rproc->virtio_features; + + return RT_EOK; +} + +static rt_err_t spacemit_rproc_virtio_set_features( + struct rt_virtio_device *vdev) +{ + struct spacemit_fw_rsc_vdev *rsc_vdev; + struct spacemit_rproc *rproc = spacemit_virtio_to_rproc(vdev); + + rsc_vdev = spacemit_rproc_rsc_vdev(rproc); + if (rsc_vdev) + { + rsc_vdev->gfeatures = rt_cpu_to_le32( + (rt_uint32_t)vdev->features); + rt_hw_wmb(); + } + + return RT_EOK; +} + +static rt_err_t spacemit_rproc_virtio_get_config( + struct rt_virtio_device *vdev, rt_uint32_t offset, void *dst, + int length) +{ + rt_memset(dst, 0, length); + + return RT_EOK; +} + +static rt_err_t spacemit_rproc_virtio_set_config( + struct rt_virtio_device *vdev, rt_uint32_t offset, + const void *src, int length) +{ + return RT_EOK; +} + +static rt_bool_t spacemit_rproc_virtio_notify(struct rt_virtqueue *vq) +{ + static const char kick[] = "kick"; + rt_ubase_t level; + struct spacemit_rproc *rproc = spacemit_virtio_to_rproc(vq->vdev); + + if (!rproc->firmware_started) + { + level = rt_spin_lock_irqsave(&spacemit_rpmsg_lock); + rproc->boot_requested = RT_TRUE; + rt_spin_unlock_irqrestore(&spacemit_rpmsg_lock, level); + + if (rproc->rpmsg_sem_inited) + { + rt_sem_release(&rproc->rpmsg_sem); + } + + LOG_D("RCPU firmware boot requested by RPMsg vq%d", vq->index); + + return RT_TRUE; + } + + if (rproc->rpmsg_ready && rproc->firmware_started && + vq->index < RT_ARRAY_SIZE(rproc->mb)) + { + ++rproc->notify_count[vq->index]; + rt_mbox_send(rproc->mb[vq->index].chan, kick, + RT_WAITING_FOREVER); + } + + return RT_TRUE; +} + +static rt_err_t spacemit_rproc_virtio_install_vqs( + struct rt_virtio_device *vdev, int vqs_nr, + struct rt_virtqueue *vqs[], const char *names[], + rt_virtqueue_callback cbs[]) +{ + struct spacemit_rproc *rproc = spacemit_virtio_to_rproc(vdev); + + if (vqs_nr != RT_ARRAY_SIZE(rproc->vqs)) + { + return -RT_EINVAL; + } + + for (int i = 0; i < vqs_nr; ++i) + { + rt_uint32_t align = rproc->vring_align[i] ? : + ARCH_PAGE_SIZE; + rt_uint16_t num = rproc->vring_num[i] ? : + K1X_RPMSG_QUEUE_NUM; + struct rt_virtqueue_formula formula = + { + .page = rproc->vring_region[i].va, + }; + + if (!names[i]) + { + vqs[i] = RT_NULL; + continue; + } + + if (rproc->vring_region[i].size < + virtq_size(RT_NULL, num, align)) + { + rt_virtio_virtqueue_release(vdev); + return -RT_EINVAL; + } + + vqs[i] = rt_virtqueue_create(vdev, names[i], i, num, align, + spacemit_rproc_virtio_notify, cbs[i], &formula); + if (!vqs[i]) + { + rt_virtio_virtqueue_release(vdev); + return -RT_ENOMEM; + } + + rproc->vqs[i] = vqs[i]; + } + + return RT_EOK; +} + +static rt_err_t spacemit_rproc_virtio_release_vqs( + struct rt_virtio_device *vdev) +{ + struct rt_virtqueue *vq, *next; + struct spacemit_rproc *rproc = spacemit_virtio_to_rproc(vdev); + + rt_list_for_each_entry_safe(vq, next, &vdev->vq_node, list) + { + if (vq->index < RT_ARRAY_SIZE(rproc->vqs)) + { + rproc->vqs[vq->index] = RT_NULL; + } + rt_virtqueue_delete(vdev, vq); + } + + return RT_EOK; +} + +static rt_err_t spacemit_rproc_virtio_control_vqs( + struct rt_virtio_device *vdev, rt_uint32_t cfg, void *data) +{ + return -RT_ENOSYS; +} + +static rt_err_t spacemit_rproc_virtio_generation( + struct rt_virtio_device *vdev, rt_uint32_t *out_counter) +{ + *out_counter = 0; + + return RT_EOK; +} + +static rt_err_t spacemit_rproc_virtio_reset( + struct rt_virtio_device *vdev) +{ + struct spacemit_rproc *rproc = spacemit_virtio_to_rproc(vdev); + + rproc->virtio_status = 0; + if (rproc->dma_slots) + { + rt_memset(rproc->dma_slots, 0, + rproc->dma_slot_count * sizeof(rproc->dma_slots[0])); + } + spacemit_rproc_virtio_set_status(vdev, 0); + + return RT_EOK; +} + +static const struct rt_virtio_transport spacemit_rproc_virtio_transport = +{ + .get_status = spacemit_rproc_virtio_get_status, + .set_status = spacemit_rproc_virtio_set_status, + .get_features = spacemit_rproc_virtio_get_features, + .set_features = spacemit_rproc_virtio_set_features, + .get_config = spacemit_rproc_virtio_get_config, + .set_config = spacemit_rproc_virtio_set_config, + .install_vqs = spacemit_rproc_virtio_install_vqs, + .release_vqs = spacemit_rproc_virtio_release_vqs, + .control_vqs = spacemit_rproc_virtio_control_vqs, + .generation = spacemit_rproc_virtio_generation, + .reset = spacemit_rproc_virtio_reset, +}; + +static void spacemit_rpmsg_notify(struct spacemit_rproc *rproc, int vq_id) +{ + static const char kick[] = "kick"; + + if (rproc->rpmsg_ready && rproc->firmware_started && + vq_id < RT_ARRAY_SIZE(rproc->mb)) + { + ++rproc->notify_count[vq_id]; + rt_mbox_send(rproc->mb[vq_id].chan, kick, RT_WAITING_FOREVER); + } +} + +static rt_err_t spacemit_rpmsg_worker_start(struct spacemit_rproc *rproc) +{ + rt_err_t err; + rt_ubase_t level; + + if (!rproc || !rproc->rpmsg_thread) + { + return -RT_EINVAL; + } + + level = rt_spin_lock_irqsave(&spacemit_rpmsg_lock); + if (rproc != spacemit_rproc_global || rproc->worker_started) + { + rt_spin_unlock_irqrestore(&spacemit_rpmsg_lock, level); + return RT_EOK; + } + rt_spin_unlock_irqrestore(&spacemit_rpmsg_lock, level); + + err = rt_thread_startup(rproc->rpmsg_thread); + if (err == RT_EOK) + { + level = rt_spin_lock_irqsave(&spacemit_rpmsg_lock); + if (rproc == spacemit_rproc_global) + { + rproc->worker_started = RT_TRUE; + } + rt_spin_unlock_irqrestore(&spacemit_rpmsg_lock, level); + + rt_sem_release(&rproc->rpmsg_sem); + LOG_D("RPMsg worker started"); + } + + return err; +} + +static void spacemit_rpmsg_pump(struct spacemit_rproc *rproc) +{ + if (!rproc || !rproc->rpmsg_ready || !rproc->firmware_started || + !rproc->rpmsg_mutex_inited) + { + return; + } + + if (rt_mutex_take(&rproc->rpmsg_mutex, RT_WAITING_NO) != RT_EOK) + { + return; + } + + for (int i = 0; i < RT_ARRAY_SIZE(rproc->vqs); ++i) + { + if (rproc->vqs[i]) + { + rt_virtqueue_isr(i, rproc->vqs[i]); + } + } + + rt_mutex_release(&rproc->rpmsg_mutex); +} + +static void spacemit_rpmsg_worker(void *parameter) +{ + struct spacemit_rproc *rproc = parameter; + + while (!rproc->worker_stop) + { + rt_bool_t boot_requested; + + rt_sem_take(&rproc->rpmsg_sem, rt_tick_from_millisecond(10)); + + boot_requested = rproc->boot_requested; + if (boot_requested && !rproc->firmware_started) + { + rt_err_t err; + rt_ubase_t level; + + level = rt_spin_lock_irqsave(&spacemit_rpmsg_lock); + rproc->boot_requested = RT_FALSE; + rt_spin_unlock_irqrestore(&spacemit_rpmsg_lock, level); + + err = spacemit_rproc_boot(rproc); + if (err) + { + LOG_E("Boot RCPU firmware failed: %s", + rt_strerror(err)); + } + else + { + spacemit_rpmsg_notify(rproc, K1X_MBOX_VQ0_ID); + spacemit_rpmsg_notify(rproc, K1X_MBOX_VQ1_ID); + } + } + + spacemit_rpmsg_pump(rproc); + } +} + +static void spacemit_rpmsg_worker_destroy(struct spacemit_rproc *rproc) +{ + rt_thread_t thread = rproc->rpmsg_thread; + + if (!thread) + { + return; + } + + rproc->worker_stop = RT_TRUE; + if (rproc->worker_started) + { + rt_sem_release(&rproc->rpmsg_sem); + rt_thread_delete(thread); + } + else + { + rt_timer_detach(&thread->thread_timer); +#ifdef RT_USING_HW_STACK_GUARD + RT_KERNEL_FREE(thread->stack_buf); +#else + RT_KERNEL_FREE(thread->stack_addr); +#endif + rt_object_delete((rt_object_t)thread); + } + + rproc->rpmsg_thread = RT_NULL; + rproc->worker_started = RT_FALSE; +} + +static rt_err_t spacemit_rpmsg_map_region_node(struct rt_ofw_node *np, + const char *label, int index, struct spacemit_rpmsg_region *region) +{ + rt_err_t err; + + if (!np) + { + return -RT_EINVAL; + } + + err = rt_ofw_get_address(np, 0, ®ion->pa, ®ion->size); + if (!err && rt_ofw_prop_read_u32(np, "da_base", ®ion->da)) + { + region->da = (rt_uint32_t)region->pa; + } + if (err) + { + rt_ofw_node_put(np); + return err; + } + + region->va = rt_ioremap_nocache((void *)(rt_ubase_t)region->pa, + region->size); + if (!region->va) + { + rt_ofw_node_put(np); + return -RT_ENOMEM; + } + + LOG_D("RPMsg %s region: %s idx=%d pa=%p da=0x%08x size=%p va=%p", + label, rt_ofw_node_full_name(np), index, + (void *)(rt_ubase_t)region->pa, region->da, + (void *)(rt_ubase_t)region->size, region->va); + + rt_ofw_node_put(np); + + return RT_EOK; +} + +static rt_err_t spacemit_rpmsg_map_region(struct spacemit_rproc *rproc, + const char *tag, int fallback_index, + struct spacemit_rpmsg_region *region) +{ + struct rt_ofw_node *np; + + for (int i = 0; i < K1X_RPMSG_MAX_MEMORY_REGIONS; ++i) + { + np = rt_ofw_parse_phandle(rproc->dev->ofw_node, + "memory-region", i); + if (!np) + { + break; + } + + if (rt_ofw_node_tag_equ(np, tag)) + { + return spacemit_rpmsg_map_region_node(np, tag, i, region); + } + + rt_ofw_node_put(np); + } + + np = rt_ofw_parse_phandle(rproc->dev->ofw_node, + "memory-region", fallback_index); + if (!np) + { + return -RT_EINVAL; + } + + LOG_W("RPMsg %s reserved memory not found by name, fallback to memory-region[%d]", + tag, fallback_index); + + return spacemit_rpmsg_map_region_node(np, tag, fallback_index, region); +} + +static rt_err_t spacemit_rpmsg_load_resource(const char *fw_name, + struct spacemit_rpmsg_region *region) +{ + rt_ubase_t base; + rt_size_t size; + Elf32_Ehdr *ehdr; + Elf32_Phdr *phdr; + + if (!spacemit_firmware_find(fw_name, &base, &size)) + { + return -RT_EEMPTY; + } + + ehdr = (Elf32_Ehdr *)base; + if (size < sizeof(*ehdr) || + rt_memcmp(ehdr->e_ident, ELFMAG, SELFMAG) || + ehdr->e_ident[EI_CLASS] != ELFCLASS32 || + ehdr->e_phoff + ehdr->e_phnum * sizeof(*phdr) > size) + { + return -RT_EINVAL; + } + + phdr = (Elf32_Phdr *)(base + ehdr->e_phoff); + for (int i = 0; i < ehdr->e_phnum; ++i) + { + rt_ubase_t offset; + rt_size_t copy; + + if (phdr[i].p_type != PT_LOAD || region->da < phdr[i].p_paddr || + region->da >= phdr[i].p_paddr + phdr[i].p_memsz) + { + continue; + } + + offset = region->da - phdr[i].p_paddr; + if (offset >= phdr[i].p_filesz || + phdr[i].p_offset + phdr[i].p_filesz > size) + { + return -RT_EINVAL; + } + + copy = rt_min_t(rt_size_t, phdr[i].p_filesz - offset, + region->size); + rt_memset(region->va, 0, region->size); + rt_memcpy(region->va, (void *)(base + phdr[i].p_offset + offset), + copy); + return RT_EOK; + } + + return -RT_EEMPTY; +} + +static rt_err_t spacemit_rproc_da_to_pa(struct spacemit_rproc *rproc, + rt_uint32_t da, rt_uint64_t *out_pa) +{ + struct rt_ofw_node *np; + + for (int i = 0; i < K1X_RPMSG_MAX_MEMORY_REGIONS; ++i) + { + rt_uint32_t da_base; + rt_uint64_t pa, size, offset; + + np = rt_ofw_parse_phandle(rproc->dev->ofw_node, + "memory-region", i); + if (!np) + { + break; + } + + if (rt_ofw_get_address(np, 0, &pa, &size)) + { + rt_ofw_node_put(np); + continue; + } + + if (rt_ofw_prop_read_u32(np, "da_base", &da_base)) + { + da_base = (rt_uint32_t)pa; + } + + if (da >= da_base) + { + offset = da - da_base; + if (offset < size) + { + *out_pa = pa + offset; + LOG_D("RCPU DA 0x%08x -> PA %p by %s idx=%d", + da, (void *)(rt_ubase_t)*out_pa, + rt_ofw_node_full_name(np), i); + rt_ofw_node_put(np); + + return RT_EOK; + } + } + + rt_ofw_node_put(np); + } + + return -RT_EINVAL; +} + +static rt_err_t spacemit_rproc_clear_carveouts(struct spacemit_rproc *rproc) +{ + struct rt_ofw_node *np; + + for (int i = 0; i < K1X_RPMSG_MAX_MEMORY_REGIONS; ++i) + { + void *va; + rt_uint64_t pa, size; + + np = rt_ofw_parse_phandle(rproc->dev->ofw_node, + "memory-region", i); + if (!np) + { + break; + } + + if (rt_ofw_get_address(np, 0, &pa, &size)) + { + rt_ofw_node_put(np); + continue; + } + + va = rt_ioremap_nocache((void *)(rt_ubase_t)pa, size); + if (!va) + { + LOG_E("Map RCPU carveout %s failed", + rt_ofw_node_full_name(np)); + rt_ofw_node_put(np); + return -RT_ENOMEM; + } + + LOG_D("Clear RCPU carveout %s pa=%p size=%p", + rt_ofw_node_full_name(np), (void *)(rt_ubase_t)pa, + (void *)(rt_ubase_t)size); + rt_memset(va, 0, size); + rt_hw_wmb(); + rt_iounmap(va); + rt_ofw_node_put(np); + } + + return RT_EOK; +} + +static rt_err_t spacemit_rpmsg_reset_transport(struct spacemit_rproc *rproc, + const char *fw_name) +{ + rt_err_t err; + struct spacemit_resource_table *table; + struct spacemit_fw_rsc_vdev *vdev; + + if (rproc->vring_region[0].size < + virtq_size(RT_NULL, K1X_RPMSG_QUEUE_NUM, ARCH_PAGE_SIZE) || + rproc->vring_region[1].size < + virtq_size(RT_NULL, K1X_RPMSG_QUEUE_NUM, ARCH_PAGE_SIZE) || + rproc->buffer_region.size < + K1X_RPMSG_QUEUE_NUM * K1X_RPMSG_BUFFER_SIZE * 2) + { + return -RT_EINVAL; + } + + if ((err = spacemit_rpmsg_load_resource(fw_name, + &rproc->rsc_region))) + { + return err; + } + + table = rproc->rsc_region.va; + if (rt_le32_to_cpu(table->num) != 1 || + rt_le32_to_cpu(table->offset[0]) + sizeof(*vdev) > + rproc->rsc_region.size) + { + return -RT_EINVAL; + } + rproc->rsc_vdev_offset = rt_le32_to_cpu(table->offset[0]); + vdev = (void *)((char *)table + rproc->rsc_vdev_offset); + if (rt_le32_to_cpu(vdev->type) != K1X_RSC_VDEV || + rt_le32_to_cpu(vdev->id) != K1X_VIRTIO_ID_RPMSG || + vdev->num_of_vrings != 2) + { + return -RT_EINVAL; + } + + rt_memset(rproc->vring_region[0].va, 0, + rproc->vring_region[0].size); + rt_memset(rproc->vring_region[1].va, 0, + rproc->vring_region[1].size); + rt_memset(rproc->buffer_region.va, 0, rproc->buffer_region.size); + + for (int i = 0; i < RT_ARRAY_SIZE(rproc->vring_region); ++i) + { + rproc->vring_num[i] = rt_le32_to_cpu(vdev->vring[i].num) ? : + K1X_RPMSG_QUEUE_NUM; + rproc->vring_align[i] = rt_le32_to_cpu(vdev->vring[i].align) ? : + ARCH_PAGE_SIZE; + rproc->vring_notify[i] = rt_le32_to_cpu(vdev->vring[i].notifyid); + } + rproc->vring_notify[0] = K1X_RPMSG_VRING0_NOTIFY_ID; + rproc->vring_notify[1] = K1X_RPMSG_VRING1_NOTIFY_ID; + + vdev->vring[0].da = rt_cpu_to_le32(rproc->vring_region[0].da); + vdev->vring[1].da = rt_cpu_to_le32(rproc->vring_region[1].da); + vdev->vring[0].align = rt_cpu_to_le32(rproc->vring_align[0]); + vdev->vring[1].align = rt_cpu_to_le32(rproc->vring_align[1]); + vdev->vring[0].num = rt_cpu_to_le32(rproc->vring_num[0]); + vdev->vring[1].num = rt_cpu_to_le32(rproc->vring_num[1]); + vdev->vring[0].notifyid = rt_cpu_to_le32(rproc->vring_notify[0]); + vdev->vring[1].notifyid = rt_cpu_to_le32(rproc->vring_notify[1]); + rproc->virtio_features = rt_le32_to_cpu(vdev->dfeatures) | + K1X_VIRTIO_RPMSG_F_NS; + vdev->dfeatures = rt_cpu_to_le32( + (rt_uint32_t)rproc->virtio_features); + vdev->gfeatures = 0; + vdev->status = 0; + rt_hw_wmb(); + + LOG_D("RPMsg resource ready: status=0x%02x notify=%u/%u vring0=0x%08x vring1=0x%08x buffer=0x%08x", + vdev->status, rproc->vring_notify[0], + rproc->vring_notify[1], + rproc->vring_region[0].da, + rproc->vring_region[1].da, rproc->buffer_region.da); + + return RT_EOK; +} + +static rt_err_t spacemit_rpmsg_prepare(struct spacemit_rproc *rproc, + const char *fw_name) +{ + rt_err_t err; + + if ((err = spacemit_rpmsg_map_region(rproc, K1X_RPMSG_VRING0_NAME, + K1X_RPMSG_VRING0_REGION, + &rproc->vring_region[0])) || + (err = spacemit_rpmsg_map_region(rproc, K1X_RPMSG_VRING1_NAME, + K1X_RPMSG_VRING1_REGION, + &rproc->vring_region[1])) || + (err = spacemit_rpmsg_map_region(rproc, K1X_RPMSG_BUFFER_NAME, + K1X_RPMSG_BUFFER_REGION, + &rproc->buffer_region)) || + (err = spacemit_rpmsg_map_region(rproc, K1X_RPMSG_RSC_NAME, + K1X_RPMSG_RSC_REGION, + &rproc->rsc_region))) + { + return err; + } + + rproc->dma_slot_count = rproc->buffer_region.size / + K1X_RPMSG_BUFFER_SIZE; + if (!rproc->dma_slot_count) + { + return -RT_EINVAL; + } + + rproc->dma_slots = rt_calloc(rproc->dma_slot_count, + sizeof(rproc->dma_slots[0])); + if (!rproc->dma_slots) + { + return -RT_ENOMEM; + } + rt_spin_lock_init(&rproc->dma_lock); + + return spacemit_rpmsg_reset_transport(rproc, fw_name); +} + +static rt_err_t spacemit_rproc_prepare(struct spacemit_rproc *rproc) +{ + rt_err_t err; + + /* Keep the RCPU held until a client explicitly needs RPMsg. */ + HWREG32(rproc->bootc_mem_base + FW_BOOTUP_REG_OFFSET) = 0; + rt_hw_wmb(); + + /* De-assert the clk */ + rt_reset_control_assert(rproc->core_rstc); + rt_reset_control_deassert(rproc->core_rstc); + HWREG32(rproc->bootc_mem_base + FW_BOOTUP_REG_OFFSET) = 0; + rt_hw_wmb(); + + /* Enable clocks explicitly (RT-Thread may keep them gated by default) */ + if ((err = rt_clk_prepare_enable(rproc->core_clk))) + { + return err; + } + + if ((err = rt_clk_prepare_enable(rproc->apb_clk))) + { + rt_clk_disable_unprepare(rproc->core_clk); + return err; + } + rproc->clocks_enabled = RT_TRUE; + + /* Set apb clk rate */ + if ((err = rt_clk_set_rate(rproc->apb_clk, rproc->apb_clk_rate))) + { + rt_clk_disable_unprepare(rproc->apb_clk); + rt_clk_disable_unprepare(rproc->core_clk); + rproc->clocks_enabled = RT_FALSE; + return err; + } + + return RT_EOK; +} + +static rt_err_t spacemit_rproc_start(struct spacemit_rproc *rproc) +{ + /* Enable ipc2ap clk & reset--> rcpu side */ + HWREG32(rproc->bootc_mem_base + FW_AON_PER_CLK_RST_CTL_REG) = 0xff; + + /* Set the boot-entry */ + HWREG32(rproc->sysctrl_mem_base + FW_BOOT_ENTRY_REG_OFFSET) = rproc->fw_entry_point; + + /* Set ddr map */ + HWREG32(rproc->sysctrl_mem_base + FW_DDR_REGMAP_BASE_REG_OFFSET) = rproc->ddr_remap_base; + + rt_hw_wmb(); + + /* Lanching up firmware */ + HWREG32(rproc->bootc_mem_base + FW_BOOTUP_REG_OFFSET) = 1; + rt_hw_wmb(); + + return RT_EOK; +} + +static rt_err_t spacemit_rproc_boot(struct spacemit_rproc *rproc) +{ + rt_err_t err; + rt_ubase_t level; + rt_bool_t started; + + if (!rproc || !rproc->rpmsg_ready || !rproc->rpmsg_mutex_inited) + { + return -RT_EINVAL; + } + + err = rt_mutex_take(&rproc->rpmsg_mutex, RT_WAITING_FOREVER); + if (err) + { + return err; + } + + level = rt_spin_lock_irqsave(&spacemit_rpmsg_lock); + if (rproc != spacemit_rproc_global) + { + rt_spin_unlock_irqrestore(&spacemit_rpmsg_lock, level); + rt_mutex_release(&rproc->rpmsg_mutex); + return -RT_EINVAL; + } + started = rproc->firmware_started; + rt_spin_unlock_irqrestore(&spacemit_rpmsg_lock, level); + + if (!started) + { + if (rproc->clocks_enabled == RT_FALSE) + { + err = spacemit_rproc_prepare(rproc); + if (err) + { + rt_mutex_release(&rproc->rpmsg_mutex); + return err; + } + } + + err = spacemit_rproc_start(rproc); + if (!err) + { + rt_hw_wmb(); + level = rt_spin_lock_irqsave(&spacemit_rpmsg_lock); + if (rproc == spacemit_rproc_global) + { + rproc->firmware_started = RT_TRUE; + rproc->boot_requested = RT_FALSE; + } + else + { + err = -RT_EINVAL; + } + rt_spin_unlock_irqrestore(&spacemit_rpmsg_lock, level); + } + } + + rt_mutex_release(&rproc->rpmsg_mutex); + if (err) + { + return err; + } + + err = spacemit_rpmsg_worker_start(rproc); + if (err) + { + return err; + } + + spacemit_rpmsg_notify(rproc, K1X_MBOX_VQ0_ID); + spacemit_rpmsg_notify(rproc, K1X_MBOX_VQ1_ID); + LOG_D("RCPU firmware booted on demand, entry=0x%08x remap=0x%08x", + rproc->fw_entry_point, rproc->ddr_remap_base); + + return RT_EOK; +} + +rt_err_t spacemit_k1x_rproc_boot(const char *fw_name) +{ + rt_err_t err; + rt_ubase_t level; + struct spacemit_rproc *rproc; + + level = rt_spin_lock_irqsave(&spacemit_rpmsg_lock); + rproc = spacemit_rproc_global; + rt_spin_unlock_irqrestore(&spacemit_rpmsg_lock, level); + + if (!rproc) + { + return -RT_ENOENT; + } + + if (fw_name && fw_name[0] && rt_strcmp(fw_name, rproc->fw_name)) + { + return -RT_ENOENT; + } + + err = spacemit_rproc_boot(rproc); + if (err) + { + LOG_E("Boot RCPU firmware %s failed: %s", + rproc->fw_name, rt_strerror(err)); + return err; + } + + return RT_EOK; +} + +void spacemit_k1x_rproc_dump_status(void) +{ + rt_ubase_t level; + struct spacemit_fw_rsc_vdev *rsc_vdev; + struct spacemit_rproc *rproc; + + level = rt_spin_lock_irqsave(&spacemit_rpmsg_lock); + rproc = spacemit_rproc_global; + rt_spin_unlock_irqrestore(&spacemit_rpmsg_lock, level); + if (!rproc) + { + LOG_W("RCPU state unavailable"); + return; + } + + LOG_W("RCPU state: started=%u worker=%u boot=%08x entry=%08x remap=%08x aon=%08x", + rproc->firmware_started, rproc->worker_started, + HWREG32((char *)rproc->bootc_mem_base + FW_BOOTUP_REG_OFFSET), + HWREG32((char *)rproc->sysctrl_mem_base + + FW_BOOT_ENTRY_REG_OFFSET), + HWREG32((char *)rproc->sysctrl_mem_base + + FW_DDR_REGMAP_BASE_REG_OFFSET), + HWREG32((char *)rproc->bootc_mem_base + + FW_AON_PER_CLK_RST_CTL_REG)); + + rsc_vdev = spacemit_rproc_rsc_vdev(rproc); + if (rsc_vdev) + { + rt_hw_rmb(); + LOG_W("RPMsg resource: status=%02x dfeatures=%08x gfeatures=%08x", + rsc_vdev->status, + rt_le32_to_cpu(rsc_vdev->dfeatures), + rt_le32_to_cpu(rsc_vdev->gfeatures)); + } + + for (int i = 0; i < RT_ARRAY_SIZE(rproc->vqs); ++i) + { + struct virtq ring; + struct rt_virtqueue *vq = rproc->vqs[i]; + + if (!vq || !rproc->vring_region[i].va) + { + continue; + } + + virtq_init(&ring, rproc->vring_num[i], + rproc->vring_region[i].va, + rproc->vring_align[i]); + rt_hw_rmb(); + LOG_W("RPMsg vq%d: avail=%u used=%u last=%u notify=%u mailbox=%u", + i, rt_le16_to_cpu(ring.avail->idx), + rt_le16_to_cpu(ring.used->idx), vq->last_used_idx, + rproc->notify_count[i], rproc->mbox_count[i]); + } +} + +static rt_err_t spacemit_rproc_stop(struct spacemit_rproc *rproc) +{ + rt_ubase_t level; + + /* Hold the rcpu */ + HWREG32(rproc->bootc_mem_base + FW_BOOTUP_REG_OFFSET) = 0; + rt_hw_wmb(); + + level = rt_spin_lock_irqsave(&spacemit_rpmsg_lock); + rproc->firmware_started = RT_FALSE; + rt_spin_unlock_irqrestore(&spacemit_rpmsg_lock, level); + + rt_reset_control_assert(rproc->core_rstc); + + if (rproc->clocks_enabled) + { + /* Gate clocks after reset asserted */ + rt_clk_disable_unprepare(rproc->apb_clk); + rt_clk_disable_unprepare(rproc->core_clk); + rproc->clocks_enabled = RT_FALSE; + } + + return RT_EOK; +} + +static void spacemit_rproc_mbox_rx_callback(struct rt_mbox_client *client, void *data) +{ + struct spacemit_rproc_mbox *mb = rt_container_of(client, struct spacemit_rproc_mbox, parent); + struct spacemit_rproc *rproc = mb->rproc; + + if (mb->vq_id < RT_ARRAY_SIZE(rproc->mbox_count)) + { + ++rproc->mbox_count[mb->vq_id]; + } + + if (rproc->rpmsg_sem_inited) + { + rt_sem_release(&rproc->rpmsg_sem); + } +} + +static rt_err_t spacemit_rproc_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + rt_uint64_t fw_entry_pa; + const char *fw_name, *name; + struct rt_device *dev = &pdev->parent; + struct spacemit_rproc *rproc = rt_calloc(1, sizeof(*rproc)); + + if (!rproc) + { + return -RT_ENOMEM; + } + rproc->dev = dev; + + rproc->bootc_mem_base = rt_dm_dev_iomap(dev, 0); + if (!rproc->bootc_mem_base) + { + err = -RT_EIO; + goto _fail; + } + + rproc->sysctrl_mem_base = rt_dm_dev_iomap(dev, 1); + if (!rproc->sysctrl_mem_base) + { + err = -RT_EIO; + goto _fail; + } + + rproc->core_rstc = rt_reset_control_get_by_index(dev, 0); + if (rt_is_err(rproc->core_rstc)) + { + err = rt_ptr_err(rproc->core_rstc); + goto _fail; + } + + rproc->core_clk = rt_clk_get_by_name(dev, "core"); + if (rt_is_err(rproc->core_clk)) + { + err = rt_ptr_err(rproc->core_clk); + goto _fail; + } + + rproc->apb_clk = rt_clk_get_by_name(dev, "apb"); + if (rt_is_err(rproc->apb_clk)) + { + err = rt_ptr_err(rproc->apb_clk); + goto _fail; + } + + if ((err = rt_dm_dev_prop_read_u32(dev, "apb-clk-rate", &rproc->apb_clk_rate))) + { + goto _fail; + } + + if ((err = rt_dm_dev_prop_read_u32(dev, "ddr-remap-base", &rproc->ddr_remap_base))) + { + goto _fail; + } + + if ((err = rt_dm_dev_prop_read_string(dev, "firmware-name", &fw_name))) + { + goto _fail; + } + rt_strncpy(rproc->fw_name, fw_name, sizeof(rproc->fw_name) - 1); + + if (!(name = rt_dm_dev_get_prop_fuzzy_name(dev, "-entry-point$"))) + { + err = -RT_EINVAL; + goto _fail; + } + + if ((err = rt_dm_dev_prop_read_u32(dev, name, &rproc->fw_entry_point))) + { + goto _fail; + } + + for (int i = 0; i < RT_ARRAY_SIZE(rproc->mb); ++i) + { + struct spacemit_rproc_mbox *mb = &rproc->mb[i]; + + mb->vq_id = i; + mb->rproc = rproc; + + mb->parent.dev = dev; + mb->parent.rx_callback = spacemit_rproc_mbox_rx_callback; + + mb->chan = rt_mbox_request_by_name(&mb->parent, mb_name[i]); + + if (rt_is_err_or_null(mb->chan)) + { + err = -RT_EINVAL; + LOG_E("Request mailbox fail"); + goto _fail; + } + } + + if ((err = spacemit_rproc_prepare(rproc))) + { + LOG_E("Prepare RCPU hardware failed: %s", rt_strerror(err)); + goto _fail; + } + + if ((err = spacemit_rproc_clear_carveouts(rproc))) + { + goto _fail; + } + + if ((err = spacemit_rproc_da_to_pa(rproc, rproc->fw_entry_point, + &fw_entry_pa))) + { + LOG_E("Translate RCPU firmware entry 0x%08x failed: %s", + rproc->fw_entry_point, rt_strerror(err)); + goto _fail; + } + if ((err = spacemit_firmware_load_elf(fw_name, fw_entry_pa))) + { + LOG_E("Run firmware %s fail", fw_name); + goto _fail; + } + + if ((err = spacemit_rpmsg_prepare(rproc, fw_name))) + { + LOG_E("Prepare RPMsg transport failed: %s", rt_strerror(err)); + goto _fail; + } + + if ((err = rt_sem_init(&rproc->rpmsg_sem, "k1-rpmsg", 0, + RT_IPC_FLAG_FIFO))) + { + goto _fail; + } + rproc->rpmsg_sem_inited = RT_TRUE; + if ((err = rt_mutex_init(&rproc->rpmsg_mutex, "k1-rpmsg", + RT_IPC_FLAG_FIFO))) + { + goto _fail; + } + rproc->rpmsg_mutex_inited = RT_TRUE; + rproc->rpmsg_thread = rt_thread_create("k1-rpmsg", spacemit_rpmsg_worker, + rproc, 4096, RT_THREAD_PRIORITY_MAX / 2, 10); + if (!rproc->rpmsg_thread) + { + err = -RT_ENOMEM; + goto _fail; + } + + rproc->rpmsg_ready = RT_TRUE; + rt_spin_lock(&spacemit_rpmsg_lock); + spacemit_rproc_global = rproc; + rt_spin_unlock(&spacemit_rpmsg_lock); + + rproc->vdev.parent.ofw_node = dev->ofw_node; + rproc->vdev.id.device = VIRTIO_DEVICE_ID_RPMSG; + rproc->vdev.id.vendor = K1X_RPMSG_VIRTIO_VENDOR; + rproc->vdev.trans = &spacemit_rproc_virtio_transport; + rproc->vdev.dma_dispatch = RT_TRUE; + rt_dma_device_set_ops(&rproc->vdev.parent, &spacemit_rproc_dma_ops); + if ((err = rt_virtio_device_register(&rproc->vdev))) + { + LOG_E("Register RCPU virtio-rpmsg failed: %s", + rt_strerror(err)); + goto _fail; + } + rproc->virtio_registered = RT_TRUE; + + LOG_D("RCPU firmware %s loaded, entry=0x%08x remap=0x%08x, boot deferred", + fw_name, rproc->fw_entry_point, rproc->ddr_remap_base); + + dev->user_data = rproc; + + return RT_EOK; + +_fail: + rproc->rpmsg_ready = RT_FALSE; + rt_spin_lock(&spacemit_rpmsg_lock); + if (spacemit_rproc_global == rproc) + { + spacemit_rproc_global = RT_NULL; + } + rt_spin_unlock(&spacemit_rpmsg_lock); + if (rproc->firmware_started) + { + spacemit_rproc_stop(rproc); + } + else if (rproc->clocks_enabled) + { + spacemit_rproc_stop(rproc); + } + if (rproc->virtio_registered) + { + rt_bus_remove_device(&rproc->vdev.parent); + rproc->virtio_registered = RT_FALSE; + } + if (rproc->rpmsg_thread) + { + spacemit_rpmsg_worker_destroy(rproc); + } + if (rproc->rpmsg_sem_inited) + { + rt_sem_detach(&rproc->rpmsg_sem); + } + if (rproc->rpmsg_mutex_inited) + { + rt_mutex_detach(&rproc->rpmsg_mutex); + } + for (int i = 0; i < RT_ARRAY_SIZE(rproc->vring_region); ++i) + { + if (rproc->vring_region[i].va) + { + rt_iounmap(rproc->vring_region[i].va); + } + } + if (rproc->buffer_region.va) + { + rt_iounmap(rproc->buffer_region.va); + } + if (rproc->rsc_region.va) + { + rt_iounmap(rproc->rsc_region.va); + } + if (rproc->dma_slots) + { + rt_free(rproc->dma_slots); + } + if (rproc->bootc_mem_base) + { + rt_iounmap(rproc->bootc_mem_base); + } + if (rproc->sysctrl_mem_base) + { + rt_iounmap(rproc->sysctrl_mem_base); + } + + if (!rt_is_err_or_null(rproc->core_rstc)) + { + rt_reset_control_put(rproc->core_rstc); + } + if (!rt_is_err_or_null(rproc->core_clk)) + { + rt_clk_put(rproc->core_clk); + } + if (!rt_is_err_or_null(rproc->apb_clk)) + { + rt_clk_put(rproc->apb_clk); + } + + for (int i = 0; i < RT_ARRAY_SIZE(rproc->mb); ++i) + { + struct spacemit_rproc_mbox *mb = &rproc->mb[i]; + + if (!rt_is_err_or_null(mb->chan)) + { + rt_mbox_release(mb->chan); + } + } + + rt_free(rproc); + + return err; +} + +static rt_err_t spacemit_rproc_shutdown(struct rt_platform_device *pdev) +{ + struct spacemit_rproc *rproc = pdev->parent.user_data; + + rproc->rpmsg_ready = RT_FALSE; + spacemit_rpmsg_worker_destroy(rproc); + if (rproc->rpmsg_mutex_inited) + { + rt_mutex_detach(&rproc->rpmsg_mutex); + rproc->rpmsg_mutex_inited = RT_FALSE; + } + if (rproc->rpmsg_sem_inited) + { + rt_sem_detach(&rproc->rpmsg_sem); + rproc->rpmsg_sem_inited = RT_FALSE; + } + rt_spin_lock(&spacemit_rpmsg_lock); + if (spacemit_rproc_global == rproc) + { + spacemit_rproc_global = RT_NULL; + } + rt_spin_unlock(&spacemit_rpmsg_lock); + if (rproc->virtio_registered) + { + rt_bus_remove_device(&rproc->vdev.parent); + rproc->virtio_registered = RT_FALSE; + } + spacemit_rproc_stop(rproc); + + return RT_EOK; +} + +static const struct rt_ofw_node_id spacemit_rproc_ofw_ids[] = +{ + { .compatible = "spacemit,k1-x-rproc" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_rproc_driver = +{ + .name = "spacemit-rproc", + .ids = spacemit_rproc_ofw_ids, + + .probe = spacemit_rproc_probe, + .shutdown = spacemit_rproc_shutdown, +}; + +static int spacemit_rproc_drv_register(void) +{ + rt_platform_driver_register(&spacemit_rproc_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(spacemit_rproc_drv_register); diff --git a/bsp/spacemit/dm/soc/k1x-tcm.c b/bsp/spacemit/dm/soc/k1x-tcm.c new file mode 100644 index 000000000000..df1d97cac362 --- /dev/null +++ b/bsp/spacemit/dm/soc/k1x-tcm.c @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include + +#define DBG_TAG "soc.k1x-tcm" +#define DBG_LVL DBG_INFO +#include + +#include +#include + +static struct rt_memheap *tcm_heap[RT_CPUS_NR]; + +void *tcm_alloc_cpu(int cpuid, rt_size_t size) +{ + if (cpuid < RT_ARRAY_SIZE(tcm_heap) && tcm_heap[cpuid]) + { + return rt_memheap_alloc(tcm_heap[cpuid], size); + } + + return RT_NULL; +} + +void tcm_free_cpu(int cpuid, void *ptr) +{ + if (cpuid < RT_ARRAY_SIZE(tcm_heap) && tcm_heap[cpuid]) + { + rt_memheap_free(ptr); + } +} + +static rt_err_t spacemit_tcm_probe(struct rt_platform_device *pdev) +{ + struct rt_ofw_node *np = pdev->parent.ofw_node, *tcm_np; + + csr_write(CSR_TCMCFG, TCM_EN); + + rt_ofw_foreach_child_node(np, tcm_np) + { + int cpuid = 0; + void *tcm_base; + rt_uint64_t addr, size; + const char *string, *node_name; + + if (rt_ofw_get_address(tcm_np, 0, &addr, &size)) + { + continue; + } + + string = node_name = rt_fdt_node_name(tcm_np->full_name); + string += sizeof("core") - 1; + + while (*string >= '0' && *string <= '9') + { + cpuid *= 10; + cpuid += *string - '0'; + + ++string; + } + + tcm_heap[cpuid] = rt_calloc(1, sizeof(struct rt_memheap)); + + if (!tcm_heap[cpuid]) + { + return -RT_ENOMEM; + } + + if (!(tcm_base = rt_ioremap_cached((void *)addr, size))) + { + rt_free(tcm_heap[cpuid]); + return -RT_EIO; + } + + if (rt_memheap_init(tcm_heap[cpuid], node_name, tcm_base, size)) + { + rt_free(tcm_heap[cpuid]); + tcm_heap[cpuid] = RT_NULL; + } + } + + return RT_EOK; +} + +static rt_err_t spacemit_tcm_shutdown(struct rt_platform_device *pdev) +{ + csr_clear(CSR_TCMCFG, TCM_EN); + + return RT_EOK; +} + +static const struct rt_ofw_node_id spacemit_tcm_ofw_ids[] = +{ + { .compatible = "spacemit,k1-x-tcm" }, + { .compatible = "spacemit,k1-pro-tcm" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_tcm_driver = +{ + .name = "spacemit-tcm", + .ids = spacemit_tcm_ofw_ids, + + .probe = spacemit_tcm_probe, + .shutdown = spacemit_tcm_shutdown, +}; + +static int spacemit_tcm_drv_register(void) +{ + rt_platform_driver_register(&spacemit_tcm_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(spacemit_tcm_drv_register); diff --git a/bsp/spacemit/dm/soc/sbi-ipi.c b/bsp/spacemit/dm/soc/sbi-ipi.c new file mode 100644 index 000000000000..3880c3522106 --- /dev/null +++ b/bsp/spacemit/dm/soc/sbi-ipi.c @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include + +#include + +static int spacemit_sbi_ipi_init(void) +{ + csr_set(CSR_IE, IE_SIE); + + return 0; +} +INIT_BOARD_EXPORT(spacemit_sbi_ipi_init); + +static int spacemit_sbi_ipi_secondary_cpu_init(void) +{ + return spacemit_sbi_ipi_init(); +} +INIT_SECONDARY_CPU_EXPORT(spacemit_sbi_ipi_secondary_cpu_init); diff --git a/bsp/spacemit/dm/soc/spacemit-socinfo.c b/bsp/spacemit/dm/soc/spacemit-socinfo.c new file mode 100644 index 000000000000..df4fdc9bbce9 --- /dev/null +++ b/bsp/spacemit/dm/soc/spacemit-socinfo.c @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include + +#define DBG_TAG "soc.info" +#define DBG_LVL DBG_INFO +#include + +struct spacemit_soc_info +{ + rt_uint32_t die_id; /* Die/wafer id */ + rt_uint32_t ver_id; /* Die/wafer version */ + rt_uint32_t pack_id; /* Package id */ + rt_uint32_t svtdro; /* Dro vaule */ + rt_uint64_t chipid; /* Chip serial number */ + rt_uint32_t soc_id; /* SoC id */ + char *name; /* Chip name */ +}; + +struct spacemit_soc_id +{ + const char *name; + rt_uint32_t id; +}; + +static const struct spacemit_soc_id soc_ids[] = +{ + { "unknown", 0x00000000 }, + /* k1 serial soc */ + { "M1-8571", 0x36070000 }, + { "K1-6370", 0x36070009 }, + { "K1-6350", 0x36070012 }, + { "K1-6371", 0x36070040 }, + { "M103-6370", 0x36070109 }, + { "M103-6371", 0x36070140 }, +}; + +static const char *soc_id_to_chip_name(rt_uint32_t die_id, rt_uint32_t ver_id, rt_uint32_t pack_id) +{ + rt_uint32_t soc_id = (die_id << 16) | (pack_id); + + for (int i = 0; i < RT_ARRAY_SIZE(soc_ids); ++i) + { + if (soc_id == soc_ids[i].id) + { + return soc_ids[i].name; + } + } + + /* The soc id is unknown */ + return soc_ids[0].name; +} + +static rt_ssize_t socinfo_get_nvparam(struct rt_device *dev, char *cell_name, void *val, rt_size_t size) +{ + rt_ssize_t res; + struct rt_nvmem_cell *cell; + + cell = rt_nvmem_get_cell_by_name(dev, cell_name); + if (rt_is_err(cell)) + { + LOG_E("NVMEM cell get %s failed", cell_name); + return rt_ptr_err(cell); + } + + res = rt_nvmem_cell_read(cell, val, rt_min_t(rt_size_t, cell->bytes, size)); + if (res < 0) + { + LOG_E("NVMEM cell read %s failed", cell_name); + goto _end; + } + +_end: + rt_nvmem_put_cell(cell); + + return res; +} + +static rt_err_t spacemit_socinfo_probe(struct rt_platform_device *pdev) +{ + rt_ssize_t res; + struct rt_device *dev = &pdev->parent; + struct spacemit_soc_info socinfo; + + rt_memset(&socinfo, 0, sizeof(socinfo)); + + if ((res = socinfo_get_nvparam(dev, "soc_die_id", + &socinfo.die_id, sizeof(socinfo.die_id))) <= 0) + { + LOG_E("Try to get soc_%s from efuse failed", "die_id"); + } + + if ((res = socinfo_get_nvparam(dev, "soc_ver_id", + &socinfo.ver_id, sizeof(socinfo.ver_id))) <= 0) + { + LOG_E("Try to get soc_%s from efuse failed", "ver_id"); + } + + if ((res = socinfo_get_nvparam(dev, "soc_pack_id", + &socinfo.pack_id, sizeof(socinfo.pack_id))) <= 0) + { + LOG_E("Try to get soc_%s from efuse failed", "pack_id"); + } + + if ((res = socinfo_get_nvparam(dev, "soc_svt_dro", + &socinfo.svtdro, sizeof(socinfo.svtdro))) <= 0) + { + LOG_E("Try to get soc_%s from efuse failed", "svt_dro"); + } + + if ((res = socinfo_get_nvparam(dev, "soc_chip_id", + &socinfo.chipid, sizeof(socinfo.chipid))) <= 0) + { + LOG_E("Try to get soc_%s from efuse failed", "chip_id"); + } + + socinfo.soc_id = (socinfo.die_id << 16) | socinfo.pack_id; + + LOG_I("Revision : %c", (socinfo.ver_id + 'A') & 0xff); + LOG_I("ID : %s", soc_id_to_chip_name(socinfo.die_id, socinfo.ver_id, socinfo.pack_id)); + LOG_I("Serial No: %016lx", socinfo.chipid); + + return RT_EOK; +} + +static const struct rt_ofw_node_id spacemit_socinfo_ofw_ids[] = +{ + { .compatible = "spacemit,socinfo-k1x" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_socinfo_driver = +{ + .name = "spacemit-socinfo", + .ids = spacemit_socinfo_ofw_ids, + + .probe = spacemit_socinfo_probe, +}; +RT_PLATFORM_DRIVER_EXPORT(spacemit_socinfo_driver); diff --git a/bsp/spacemit/dm/soc/v2d/SConscript b/bsp/spacemit/dm/soc/v2d/SConscript new file mode 100644 index 000000000000..d5a33a71dd12 --- /dev/null +++ b/bsp/spacemit/dm/soc/v2d/SConscript @@ -0,0 +1,9 @@ +from building import * + +cwd = GetCurrentDir() +src = ['v2d_drv.c', 'v2d_hw.c'] +CPPPATH = [cwd, cwd + '/../../include'] + +group = DefineGroup('DeviceDrivers', src, depend = ['RT_SOC_SPACEMIT_V2D'], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/soc/v2d/v2d_drv.c b/bsp/spacemit/dm/soc/v2d/v2d_drv.c new file mode 100644 index 000000000000..38825126c8bd --- /dev/null +++ b/bsp/spacemit/dm/soc/v2d/v2d_drv.c @@ -0,0 +1,740 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include "v2d_internal.h" +#include "v2d_reg.h" + +#include + +#define V2D_TIMEOUT_MS 2500 +#define V2D_CORE_RATE 409600000UL +#define V2D_ADDRESS_MASK 0x3ffffffffULL + +struct spacemit_v2d_buffer +{ + rt_list_t list; + V2D_BUFFER_S buffer; +}; + +struct spacemit_v2d +{ + struct rt_device parent; + struct rt_device *dev; + void *regs; + int irq; + + struct rt_clk *clk_core; + struct rt_clk *clk_io; + struct rt_reset_control *reset; + + struct rt_mutex lock; + struct rt_completion completion; + rt_list_t buffers; + + rt_bool_t clocks_enabled; + rt_bool_t reset_deasserted; + rt_bool_t lock_initialized; + rt_bool_t device_registered; + + rt_uint32_t irq_status; + rt_uint32_t error_status; + rt_err_t error; +}; + +rt_inline struct spacemit_v2d *raw_to_spacemit_v2d(struct rt_device *dev) +{ + return rt_container_of(dev, struct spacemit_v2d, parent); +} + +static rt_uint64_t v2d_surface_y_address(const V2D_SURFACE_S *surface) +{ + return (rt_uint64_t)surface->phyaddr_y_l | + ((rt_uint64_t)surface->phyaddr_y_h << 32); +} + +static rt_uint64_t v2d_surface_uv_address(const V2D_SURFACE_S *surface) +{ + return (rt_uint64_t)surface->phyaddr_uv_l | + ((rt_uint64_t)surface->phyaddr_uv_h << 32); +} + +static int v2d_format_bpp(V2D_COLOR_FORMAT_E format) +{ + switch (format) + { + case V2D_COLOR_FORMAT_NV12: + case V2D_COLOR_FORMAT_NV21: + case V2D_COLOR_FORMAT_A8: + case V2D_COLOR_FORMAT_Y8: + case V2D_COLOR_FORMAT_L8_RGBA8888: + case V2D_COLOR_FORMAT_L8_RGB888: + case V2D_COLOR_FORMAT_L8_RGB565: + case V2D_COLOR_FORMAT_L8_BGRA8888: + case V2D_COLOR_FORMAT_L8_BGR888: + case V2D_COLOR_FORMAT_L8_BGR565: + return 1; + case V2D_COLOR_FORMAT_RGB565: + case V2D_COLOR_FORMAT_BGR565: + return 2; + case V2D_COLOR_FORMAT_RGB888: + case V2D_COLOR_FORMAT_BGR888: + case V2D_COLOR_FORMAT_RGBA5658: + case V2D_COLOR_FORMAT_ARGB8565: + case V2D_COLOR_FORMAT_BGRA5658: + case V2D_COLOR_FORMAT_ABGR8565: + return 3; + case V2D_COLOR_FORMAT_RGBX8888: + case V2D_COLOR_FORMAT_RGBA8888: + case V2D_COLOR_FORMAT_ARGB8888: + case V2D_COLOR_FORMAT_BGRX8888: + case V2D_COLOR_FORMAT_BGRA8888: + case V2D_COLOR_FORMAT_ABGR8888: + return 4; + default: + return 0; + } +} + +static rt_bool_t v2d_range_is_allocated(struct spacemit_v2d *v2d, + rt_uint64_t address, rt_uint64_t size) +{ + struct spacemit_v2d_buffer *entry; + + if (!address || !size || address > V2D_ADDRESS_MASK || + size - 1 > V2D_ADDRESS_MASK - address) + { + return RT_FALSE; + } + + rt_list_for_each_entry(entry, &v2d->buffers, list) + { + rt_uint64_t start = entry->buffer.phys_addr; + rt_uint64_t end = start + entry->buffer.size; + + if (address >= start && address + size <= end) + { + return RT_TRUE; + } + } + + return RT_FALSE; +} + +static rt_err_t v2d_validate_rect(const V2D_AREA_S *rect, + rt_uint16_t width, rt_uint16_t height) +{ + if (!rect->w || !rect->h || rect->x >= width || rect->y >= height || + rect->w > width - rect->x || rect->h > height - rect->y) + { + return -RT_EINVAL; + } + + return RT_EOK; +} + +static rt_err_t v2d_validate_surface(struct spacemit_v2d *v2d, + const V2D_SURFACE_S *surface, const V2D_AREA_S *rect) +{ + rt_uint64_t y_size; + rt_uint64_t min_stride; + rt_uint64_t address; + int bpp; + + if (surface->fbc_enable) + { + return -RT_ENOSYS; + } + if (!surface->w || !surface->h || !surface->stride || + !(bpp = v2d_format_bpp(surface->format))) + { + return -RT_EINVAL; + } + if (v2d_validate_rect(rect, surface->w, surface->h) != RT_EOK) + { + return -RT_EINVAL; + } + + min_stride = (rt_uint64_t)surface->w * bpp; + if (surface->stride < min_stride) + { + return -RT_EINVAL; + } + + address = v2d_surface_y_address(surface); + y_size = (rt_uint64_t)(surface->h - 1) * surface->stride + min_stride; + if (!v2d_range_is_allocated(v2d, address, y_size)) + { + return -RT_EINVAL; + } + + if (surface->format == V2D_COLOR_FORMAT_NV12 || + surface->format == V2D_COLOR_FORMAT_NV21) + { + rt_uint64_t uv_address = v2d_surface_uv_address(surface); + rt_uint64_t uv_size = (rt_uint64_t)surface->stride * + RT_DIV_ROUND_UP(surface->h, 2); + + if (!v2d_range_is_allocated(v2d, uv_address, uv_size)) + { + return -RT_EINVAL; + } + } + + return RT_EOK; +} + +static rt_bool_t v2d_layer_enabled(const V2D_SURFACE_S *surface) +{ + return surface->solidcolor.enable || surface->fbc_enable || + v2d_surface_y_address(surface) != 0; +} + +static rt_bool_t v2d_blend_layer_valid(const V2D_BLEND_LAYER_CONF_S *blend, + V2D_BLENDCMD_E command) +{ + if ((unsigned int)blend->blend_alpha_source >= + V2D_BLENDALPHA_SOURCE_BUTT || + (unsigned int)blend->blend_pre_alpha_func >= + V2D_BLEND_PRE_ALPHA_FUNC_BUTT) + { + return RT_FALSE; + } + + if (command == V2D_BLENDCMD_ALPHA) + { + return (unsigned int)blend->stBlendFactor.srcColorFactor < + V2D_BLEND_BUTT && + (unsigned int)blend->stBlendFactor.dstColorFactor < + V2D_BLEND_BUTT && + (unsigned int)blend->stBlendFactor.srcAlphaFactor < + V2D_BLEND_BUTT && + (unsigned int)blend->stBlendFactor.dstAlphaFactor < + V2D_BLEND_BUTT; + } + + return (unsigned int)blend->stRop2Code.colorRop2Code < V2D_ROP2_BUTT && + (unsigned int)blend->stRop2Code.alphaRop2Code < V2D_ROP2_BUTT; +} + +static rt_err_t v2d_validate_layer(struct spacemit_v2d *v2d, + const V2D_SURFACE_S *surface, const V2D_AREA_S *source, + const V2D_BLEND_LAYER_CONF_S *blend, const V2D_SURFACE_S *dst) +{ + if (!v2d_layer_enabled(surface)) + { + return RT_EOK; + } + if (!blend->blend_area.w || !blend->blend_area.h || + blend->blend_area.x >= dst->w || blend->blend_area.y >= dst->h || + blend->blend_area.w > dst->w - blend->blend_area.x || + blend->blend_area.h > dst->h - blend->blend_area.y) + { + return -RT_EINVAL; + } + if (surface->solidcolor.enable) + { + return surface->solidcolor.fillcolor.format < V2D_COLOR_FORMAT_BUTT ? + RT_EOK : -RT_EINVAL; + } + + return v2d_validate_surface(v2d, surface, source); +} + +static rt_err_t v2d_validate_task(struct spacemit_v2d *v2d, + V2D_SUBMIT_TASK_S *task) +{ + V2D_PARAM_S *param; + rt_err_t err; + + if (!task) + { + return -RT_EINVAL; + } + param = &task->param; + + if (task->acquireFencefd != -1 || + param->dst.fbc_enable || param->mask.fbc_enable || + (unsigned int)param->l0_rt > V2D_ROT_FLIP || + (unsigned int)param->l1_rt > V2D_ROT_FLIP || + (unsigned int)param->l0_csc > V2D_CSC_MODE_BUTT || + (unsigned int)param->l1_csc > V2D_CSC_MODE_BUTT || + (unsigned int)param->dither > V2D_DITHER_8X8 || + (unsigned int)param->blendconf.blend_cmd >= V2D_BLENDCMD_BUTT || + (unsigned int)param->blendconf.mask_cmd >= V2D_MASKCMD_BUTT || + param->palette.len < 0 || + param->palette.len > (int)sizeof(param->palette.palVal) || + !v2d_blend_layer_valid(¶m->blendconf.blendlayer[0], + param->blendconf.blend_cmd) || + !v2d_blend_layer_valid(¶m->blendconf.blendlayer[1], + param->blendconf.blend_cmd)) + { + return -RT_EINVAL; + } + if ((err = v2d_validate_surface(v2d, ¶m->dst, + ¶m->dst_rect)) != RT_EOK) + { + return err; + } + if ((err = v2d_validate_layer(v2d, ¶m->layer0, ¶m->l0_rect, + ¶m->blendconf.blendlayer[0], ¶m->dst)) != RT_EOK) + { + return err; + } + if ((err = v2d_validate_layer(v2d, ¶m->layer1, ¶m->l1_rect, + ¶m->blendconf.blendlayer[1], ¶m->dst)) != RT_EOK) + { + return err; + } + if (!v2d_layer_enabled(¶m->layer0) && + !v2d_layer_enabled(¶m->layer1) && + !param->blendconf.bgcolor.enable) + { + return -RT_EINVAL; + } + if (v2d_surface_y_address(¶m->mask)) + { + if ((err = v2d_validate_surface(v2d, ¶m->mask, + ¶m->mask_rect)) != RT_EOK) + { + return err; + } + } + + return RT_EOK; +} + +static rt_err_t v2d_buffer_alloc(struct spacemit_v2d *v2d, + V2D_BUFFER_S *buffer) +{ + struct spacemit_v2d_buffer *entry; + rt_ubase_t phys_addr; + + if (!buffer || !buffer->size || buffer->size > V2D_BUFFER_MAX_SIZE) + { + return -RT_EINVAL; + } + + entry = rt_calloc(1, sizeof(*entry)); + if (!entry) + { + return -RT_ENOMEM; + } + + buffer->virt_addr = rt_dma_alloc_coherent(v2d->dev, buffer->size, + &phys_addr); + if (!buffer->virt_addr) + { + rt_free(entry); + return -RT_ENOMEM; + } + buffer->phys_addr = phys_addr; + entry->buffer = *buffer; + rt_list_insert_before(&v2d->buffers, &entry->list); + + return RT_EOK; +} + +static rt_err_t v2d_buffer_free(struct spacemit_v2d *v2d, + V2D_BUFFER_S *buffer) +{ + struct spacemit_v2d_buffer *entry; + + if (!buffer || !buffer->virt_addr || !buffer->size) + { + return -RT_EINVAL; + } + + rt_list_for_each_entry(entry, &v2d->buffers, list) + { + if (entry->buffer.virt_addr == buffer->virt_addr && + entry->buffer.phys_addr == buffer->phys_addr && + entry->buffer.size == buffer->size) + { + rt_list_remove(&entry->list); + rt_dma_free_coherent(v2d->dev, entry->buffer.size, + entry->buffer.virt_addr, entry->buffer.phys_addr); + rt_free(entry); + buffer->virt_addr = RT_NULL; + buffer->phys_addr = 0; + return RT_EOK; + } + } + + return -RT_EINVAL; +} + +static rt_err_t v2d_hard_reset(struct spacemit_v2d *v2d) +{ + rt_err_t err; + + v2d_irq_disable(); + if (!rt_is_err_or_null(v2d->reset)) + { + if ((err = rt_reset_control_assert(v2d->reset)) != RT_EOK) + { + return err; + } + v2d->reset_deasserted = RT_FALSE; + rt_hw_us_delay(5); + if ((err = rt_reset_control_deassert(v2d->reset)) != RT_EOK) + { + return err; + } + v2d->reset_deasserted = RT_TRUE; + } + + return v2d_global_reset(); +} + +static rt_err_t v2d_submit(struct spacemit_v2d *v2d, + V2D_SUBMIT_TASK_S *task) +{ + rt_uint32_t status; + rt_err_t err; + + if ((err = v2d_validate_task(v2d, task)) != RT_EOK) + { + return err; + } + task->completeFencefd = -1; + + status = v2d_irq_status(); + if (status) + { + v2d_irq_clear(status); + } + status = v2d_irqerr_status(); + if (status) + { + v2d_irqerr_clear(status); + } + + rt_completion_init(&v2d->completion); + v2d->irq_status = 0; + v2d->error_status = 0; + v2d->error = RT_EOK; + + v2d_irq_enable(); + config_v2d_hw(task); + + if (rt_completion_wait(&v2d->completion, + rt_tick_from_millisecond(V2D_TIMEOUT_MS)) != RT_EOK) + { + LOG_E("job timeout"); + v2d_dump_irqraw_status(); + v2d_hard_reset(v2d); + return -RT_ETIMEOUT; + } + + v2d_irq_disable(); + if (v2d->error != RT_EOK) + { + LOG_E("job failed: irq=%08x error=%08x", + v2d->irq_status, v2d->error_status); + v2d_dump_irqraw_status(); + v2d_hard_reset(v2d); + } + + return v2d->error; +} + +static rt_err_t spacemit_v2d_control(rt_device_t dev, int cmd, void *args) +{ + rt_err_t err; + struct spacemit_v2d *v2d = raw_to_spacemit_v2d(dev); + + rt_mutex_take(&v2d->lock, RT_WAITING_FOREVER); + + switch (cmd) + { + case V2D_SUBMIT: + err = v2d_submit(v2d, args); + break; + case V2D_ALLOC_BUFFER: + err = v2d_buffer_alloc(v2d, args); + break; + case V2D_FREE_BUFFER: + err = v2d_buffer_free(v2d, args); + break; + case V2D_RESET: + err = v2d_hard_reset(v2d); + break; + default: + err = -RT_ENOSYS; + break; + } + + rt_mutex_release(&v2d->lock); + + return err; +} + +#ifdef RT_USING_DEVICE_OPS +static const struct rt_device_ops spacemit_v2d_ops = +{ + .control = spacemit_v2d_control, +}; +#endif + +static void spacemit_v2d_isr(int irqno, void *param) +{ + rt_uint32_t irq_status; + rt_uint32_t error_status; + struct spacemit_v2d *v2d = param; + + RT_UNUSED(irqno); + + irq_status = v2d_irq_status(); + error_status = v2d_irqerr_status(); + + if (error_status) + { + v2d_irqerr_clear(error_status); + v2d->error_status |= error_status; + v2d->error = -RT_EIO; + } + if (irq_status) + { + v2d_irq_clear(irq_status); + v2d->irq_status |= irq_status; + } + + if (error_status || (irq_status & + (V2D_EOF_IRQ_STATUS | V2D_FBCENC_IRQ_STATUS))) + { + rt_completion_done(&v2d->completion); + } +} + +static rt_err_t v2d_clocks_enable(struct spacemit_v2d *v2d) +{ + rt_err_t err; + + if ((err = rt_clk_prepare_enable(v2d->clk_core)) != RT_EOK) + { + return err; + } + if ((err = rt_clk_prepare_enable(v2d->clk_io)) != RT_EOK) + { + rt_clk_disable_unprepare(v2d->clk_core); + return err; + } + + v2d->clocks_enabled = RT_TRUE; + + return RT_EOK; +} + +static void v2d_clocks_disable(struct spacemit_v2d *v2d) +{ + if (!v2d->clocks_enabled) + { + return; + } + + if (!rt_is_err_or_null(v2d->clk_io)) + { + rt_clk_disable_unprepare(v2d->clk_io); + } + if (!rt_is_err_or_null(v2d->clk_core)) + { + rt_clk_disable_unprepare(v2d->clk_core); + } + v2d->clocks_enabled = RT_FALSE; +} + +static void spacemit_v2d_free(struct spacemit_v2d *v2d) +{ + struct spacemit_v2d_buffer *entry, *next; + + if (v2d->dev && v2d->dev->user_data == v2d) + { + v2d->dev->user_data = RT_NULL; + } + + rt_list_for_each_entry_safe(entry, next, &v2d->buffers, list) + { + rt_list_remove(&entry->list); + rt_dma_free_coherent(v2d->dev, entry->buffer.size, + entry->buffer.virt_addr, entry->buffer.phys_addr); + rt_free(entry); + } + + if (v2d->device_registered) + { + rt_device_unregister(&v2d->parent); + v2d->device_registered = RT_FALSE; + } + if (v2d->lock_initialized) + { + rt_mutex_detach(&v2d->lock); + v2d->lock_initialized = RT_FALSE; + } + + if (v2d->reset_deasserted && !rt_is_err_or_null(v2d->reset)) + { + rt_reset_control_assert(v2d->reset); + v2d->reset_deasserted = RT_FALSE; + } + + v2d_clocks_disable(v2d); + + if (!rt_is_err_or_null(v2d->clk_io)) + { + rt_clk_put(v2d->clk_io); + } + if (!rt_is_err_or_null(v2d->clk_core)) + { + rt_clk_put(v2d->clk_core); + } + if (!rt_is_err_or_null(v2d->reset)) + { + rt_reset_control_put(v2d->reset); + } + if (v2d->regs) + { + v2d_hw_set_base(RT_NULL); + rt_iounmap(v2d->regs); + } + + rt_free(v2d); +} + +static rt_err_t spacemit_v2d_probe(struct rt_platform_device *pdev) +{ + const char *dev_name; + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct spacemit_v2d *v2d = rt_calloc(1, sizeof(*v2d)); + + if (!v2d) + { + return -RT_ENOMEM; + } + v2d->dev = dev; + rt_list_init(&v2d->buffers); + + v2d->regs = rt_dm_dev_iomap(dev, 0); + if (!v2d->regs) + { + err = -RT_EIO; + goto _fail; + } + v2d_hw_set_base(v2d->regs); + + v2d->clk_core = rt_clk_get_by_name(dev, "v2d-core"); + if (rt_is_err(v2d->clk_core)) + { + err = rt_ptr_err(v2d->clk_core); + goto _fail; + } + v2d->clk_io = rt_clk_get_by_name(dev, "v2d-io"); + if (rt_is_err(v2d->clk_io)) + { + err = rt_ptr_err(v2d->clk_io); + goto _fail; + } + if ((err = v2d_clocks_enable(v2d)) != RT_EOK) + { + goto _fail; + } + if ((err = rt_clk_set_rate(v2d->clk_core, V2D_CORE_RATE)) != RT_EOK) + { + goto _fail; + } + + v2d->reset = rt_reset_control_get_by_name(dev, "v2d_reset"); + if (rt_is_err(v2d->reset)) + { + err = rt_ptr_err(v2d->reset); + goto _fail; + } + if ((err = rt_reset_control_deassert(v2d->reset)) != RT_EOK) + { + goto _fail; + } + v2d->reset_deasserted = RT_TRUE; + if ((err = v2d_global_reset()) != RT_EOK) + { + goto _fail; + } + + v2d->irq = rt_dm_dev_get_irq(dev, 0); + if (v2d->irq < 0) + { + err = v2d->irq; + goto _fail; + } + + if ((err = rt_dm_dev_set_name_auto(&v2d->parent, "v2d")) < 0) + { + goto _fail; + } + dev_name = rt_dm_dev_get_name(&v2d->parent); + v2d->parent.type = RT_Device_Class_Char; +#ifdef RT_USING_DEVICE_OPS + v2d->parent.ops = &spacemit_v2d_ops; +#else + v2d->parent.control = spacemit_v2d_control; +#endif + dev->user_data = v2d; + + if ((err = rt_mutex_init(&v2d->lock, dev_name, + RT_IPC_FLAG_PRIO)) != RT_EOK) + { + goto _fail; + } + v2d->lock_initialized = RT_TRUE; + rt_completion_init(&v2d->completion); + + if ((err = rt_device_register(&v2d->parent, dev_name, + RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE)) != RT_EOK) + { + goto _fail; + } + v2d->device_registered = RT_TRUE; + + v2d_irq_disable(); + + rt_hw_interrupt_install(v2d->irq, spacemit_v2d_isr, v2d, "v2d"); + rt_hw_interrupt_umask(v2d->irq); + + return RT_EOK; + +_fail: + spacemit_v2d_free(v2d); + return err; +} + +static rt_err_t spacemit_v2d_remove(struct rt_platform_device *pdev) +{ + struct spacemit_v2d *v2d = pdev->parent.user_data; + + rt_hw_interrupt_mask(v2d->irq); + rt_pic_detach_irq(v2d->irq, v2d); + spacemit_v2d_free(v2d); + + return RT_EOK; +} + +static const struct rt_ofw_node_id spacemit_v2d_ofw_ids[] = +{ + { .compatible = "spacemit,v2d" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spacemit_v2d_driver = +{ + .name = "spacemit-v2d", + .ids = spacemit_v2d_ofw_ids, + .probe = spacemit_v2d_probe, + .remove = spacemit_v2d_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(spacemit_v2d_driver); diff --git a/bsp/spacemit/dm/soc/v2d/v2d_hw.c b/bsp/spacemit/dm/soc/v2d/v2d_hw.c new file mode 100644 index 000000000000..603774626dbd --- /dev/null +++ b/bsp/spacemit/dm/soc/v2d/v2d_hw.c @@ -0,0 +1,1092 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include "v2d_internal.h" +#include "v2d_reg.h" + +static const int cscmatrix[V2D_CSC_MODE_BUTT][3][4] = +{ + /* RGB2BT601Wide */ + {{ 306, 601, 117, 0 }, + { -173, -339, 512, 128 }, + { 512, -429, -83, 128 }}, + + /* BT601Wide2RGB */ + {{ 1024, 0, 1436, -179 }, + { 1024, -352, -731, 135 }, + { 1024, 1815, 0, -227 }}, + + /* RGB2BT601Narrow */ + {{ 263, 516, 100, 16 }, + { -152, -298, 450, 128 }, + { 450, -377, -73, 128 }}, + + /* BT601Narrow2RGB */ + {{ 1192, 0, 1634, -223 }, + { 1192, -401, -832, 136 }, + { 1192, 2066, 0, -277 }}, + + /* RGB2BT709Wide */ + {{ 218, 732, 74, 0 }, + { -117, -395, 512, 128 }, + { 512, -465, -47, 128 }}, + + /* BT709Wide2RGB */ + {{ 1024, 0, 1613, -202 }, + { 1024, -192, -479, 84 }, + { 1024, 1900, 0, -238 }}, + + /* RGB2BT709Narrow */ + {{ 187, 629, 63, 16 }, + { -103, -347, 450, 128}, + { 450, -409, -41, 128}}, + + /* BT709Narrow2RGB */ + {{ 1192, 0, 1836, -248 }, + { 1192, -218, -546, 77 }, + { 1192, 2163, 0, -289 }}, + + /* BT601Wide2BT709Wide */ + {{ 1024, -121, -218, 42 }, + { 0, 1043, 117, -17 }, + { 0, 77, 1050, -13 }}, + + /* BT601Wide2BT709Narrow */ + {{ 879, -104, -187, 52 }, + { 0, 916, 103, 1 }, + { 0, 68, 922, 4 }}, + + /* BT601Wide2BT601Narrow */ + {{ 879, 0, 0, 16 }, + { 0, 900, 0, 16 }, + { 0, 0, 900, 16 }}, + + /* BT601Narrow2BT709Wide */ + {{ 1192, -138, -248, 30 }, + { 0, 1187, 134, -37 }, + { 0, 88, 1195, -32 }}, + + /* BT601Narrow2BT709Narrow */ + {{ 1024, -118, -213, 41 }, + { 0, 1043, 117, -17 }, + { 0, 77, 1050, -13 }}, + + /* BT601Narrow2BT601Wide */ + {{ 1192, 0, 0, -19 }, + { 0, 1166, 0, -18 }, + { 0, 0, 1166, -18 }}, + + /* BT709Wide2BT601Wide */ + {{ 1024, 104, 201, -38 }, + { 0, 1014, -113, 15 }, + { 0, -74, 1007, 11 }}, + + /* BT709Wide2BT601Narrow */ + {{ 879, 89, 172, -17 }, + { 0, 890, -100, 29 }, + { 0, -65, 885, 26 }}, + + /* BT709Wide2BT709Narrow */ + {{ 879, 0, 0, 16 }, + { 0, 900, 0, 16 }, + { 0, 0, 900, 16 }}, + + /* BT709Narrow2BT601Wide */ + {{ 1192, 118, 229, -62 }, + { 0, 1154, -129, 0 }, + { 0, -85, 1146, -5 }}, + + /* BT709Narrow2BT601Narrow */ + {{ 1024, 102, 196, -37 }, + { 0, 1014, -113, 15 }, + { 0, -74, 1007, 11 }}, + + /* BT709Narrow2BT709Wide */ + {{ 1192, 0, 0, -19 }, + { 0, 1166, 0, -18 }, + { 0, 0, 1166, -18 }}, + + /* RGB2Grey */ + {{ 218, 732, 74, 0 }, + { -117, -395, 512, 128 }, + { 512, -465, -47, 128 }}, + + /* RGB2RGB */ + {{ 1024, 0, 0, 0 }, + { 0, 1024, 0, 0 }, + { 0, 0, 1024, 0 }} +}; + +enum +{ + R = 0, + G, + B, + A +}; + +static const int32_t bicubic_coef[16][3] = +{ + { 246, 507, 246 }, + { 222, 505, 270 }, + { 199, 501, 294 }, + { 177, 494, 318 }, + { 155, 486, 342 }, + { 136, 474, 365 }, + { 117, 461, 387 }, + { 100, 445, 408 }, + { 85, 427, 427 }, + { 71, 408, 445 }, + { 59, 387, 461 }, + { 49, 365, 474 }, + { 41, 343, 485 }, + { 35, 318, 494 }, + { 30, 294, 501 }, + { 27, 270, 505 } +}; + +static void *v2d_reg_base; + +void v2d_hw_set_base(void *base) +{ + v2d_reg_base = base; +} + +rt_inline void v2d_write(uint32_t reg, uint32_t val) +{ + HWREG32((rt_uint8_t *)v2d_reg_base + reg) = val; +} + +rt_inline uint32_t v2d_read(uint32_t reg) +{ + return HWREG32((rt_uint8_t *)v2d_reg_base + reg); +} + +rt_inline void v2d_set_bits(uint32_t reg, uint32_t bits) +{ + v2d_write(reg, v2d_read(reg) | bits); +} + +rt_inline void v2d_clear_bits(uint32_t reg, uint32_t bits) +{ + v2d_write(reg, v2d_read(reg) & ~bits); +} + +static void v2d_write_bits(uint32_t reg, uint32_t value, uint32_t mask, uint32_t shifts) +{ + uint32_t reg_val; + + reg_val = v2d_read(reg); + reg_val &= ~(mask << shifts); + reg_val |= (value << shifts); + v2d_write(reg, reg_val); +} + +int v2d_global_reset(void) +{ + int timeout = 10000; + + v2d_set_bits(V2D_AUTO_CLK_REG, V2D_GLOBAL_RESET); + while ((v2d_read(V2D_AUTO_CLK_REG) & V2D_GLOBAL_RESET) && --timeout) + { + rt_hw_us_delay(1); + } + + if (!timeout) + { + LOG_E("global reset timeout"); + return -RT_ETIMEOUT; + } + + return RT_EOK; +} + +uint32_t v2d_irq_status(void) +{ + return v2d_read(V2D_IRQ_STATUS); +} + +void v2d_dump_irqraw_status(void) +{ + uint32_t irqerr_raw, encirq, dec0_irqraw, dec1_irqraw; + irqerr_raw = v2d_read(V2D_ERR_IRQ_RAW); + dec0_irqraw = v2d_read(V2D_L0_DEC_REG8); + dec1_irqraw = v2d_read(V2D_L1_DEC_REG8); + encirq = v2d_read(V2D_ENC_REG18); + LOG_E("raw status: core=%08x dec0=%08x dec1=%08x enc=%08x", + irqerr_raw, dec0_irqraw, dec1_irqraw, encirq); +} + +uint32_t v2d_irqerr_status(void) +{ + return v2d_read(V2D_ERR_IRQ_STATUS); +} + +void v2d_irqerr_clear(uint32_t irqerr) +{ + v2d_write(V2D_ERR_IRQ_STATUS, irqerr); +} + +void v2d_irq_clear(uint32_t irqstaus) +{ + v2d_write(V2D_ENC_REG18, 0x3ffff); + v2d_write(V2D_IRQ_STATUS, irqstaus); +} + +void v2d_irq_enable(void) +{ + v2d_write(V2D_IRQ_MASK, V2D_EOF_IRQ_MASK|V2D_FBCENC_IRQ_MASK); + v2d_write(V2D_ERR_IRQ_MASK, 0xE07); + v2d_write_bits(V2D_DEBUG_REG0, 0x1, 0x1, 0); +} + +void v2d_irq_disable(void) +{ + v2d_write(V2D_IRQ_MASK, 0x00); + v2d_write(V2D_ERR_IRQ_MASK, 0x00); +} + +static void ConfigAxiBus(void) +{ + v2d_axi_bus_ctrl_reg_t ctrl; + + ctrl.overlay = 0; + ctrl.field.arqos_m = 2; + ctrl.field.awqos_m = 2; + ctrl.field.shadow_mode = 1; + v2d_write(V2D_AXI_BUS_CTRL, ctrl.overlay); +} + +int getBytePerPixel(V2D_COLOR_FORMAT_E enFormat) +{ + int Bpp=0; + + switch (enFormat) + { + case V2D_COLOR_FORMAT_NV12: + case V2D_COLOR_FORMAT_NV21: + Bpp = 1; + break; + case V2D_COLOR_FORMAT_RGB888: + case V2D_COLOR_FORMAT_BGR888: + Bpp = 3; + break; + case V2D_COLOR_FORMAT_RGBX8888: + case V2D_COLOR_FORMAT_RGBA8888: + case V2D_COLOR_FORMAT_ARGB8888: + case V2D_COLOR_FORMAT_BGRX8888: + case V2D_COLOR_FORMAT_BGRA8888: + case V2D_COLOR_FORMAT_ABGR8888: + Bpp = 4; + break; + case V2D_COLOR_FORMAT_RGB565: + case V2D_COLOR_FORMAT_BGR565: + Bpp = 2; + break; + case V2D_COLOR_FORMAT_RGBA5658: + case V2D_COLOR_FORMAT_ARGB8565: + case V2D_COLOR_FORMAT_BGRA5658: + case V2D_COLOR_FORMAT_ABGR8565: + Bpp = 3; + break; + case V2D_COLOR_FORMAT_A8: + case V2D_COLOR_FORMAT_Y8: + Bpp = 1; + break; + default: + LOG_E("err format: %d not supported",enFormat); + } + return Bpp; +} + +static void v2d_scaler_coef_init(void) +{ + const int32_t *pCoef; + v2d_scaler_coef_reg_t scaler_coef; + + scaler_coef.overlay = 0; + pCoef = &bicubic_coef[0][0]; + for (int i=0; i> 8) & 0xFF; + b = (fillcolor >> 16) & 0xFF; + a = 0xFF; + break; + case V2D_COLOR_FORMAT_NV21: + r = fillcolor & 0xFF; + b = (fillcolor >> 8) & 0xFF; + g = (fillcolor >> 16) & 0xFF; + a = 0xFF; + break; + case V2D_COLOR_FORMAT_RGB888: + case V2D_COLOR_FORMAT_RGBX8888: + r = fillcolor & 0xFF; + g = (fillcolor >> 8) & 0xFF; + b = (fillcolor >> 16) & 0xFF; + a = 0xFF; + break; + case V2D_COLOR_FORMAT_RGBA8888: + r = fillcolor & 0xFF; + g = (fillcolor >> 8) & 0xFF; + b = (fillcolor >> 16) & 0xFF; + a = (fillcolor >> 24) & 0xFF; + break; + case V2D_COLOR_FORMAT_ARGB8888: + a = fillcolor & 0xFF; + r = (fillcolor >> 8) & 0xFF; + g = (fillcolor >> 16) & 0xFF; + b = (fillcolor >> 24) & 0xFF; + break; + case V2D_COLOR_FORMAT_RGB565: + a = 0xFF; + r = fillcolor & 0x1F; + g = (fillcolor >> 5) & 0x3F; + b = (fillcolor >> 11) & 0x1F; + break; + case V2D_COLOR_FORMAT_RGBA5658: + r = fillcolor & 0x1F; + g = (fillcolor >> 5) & 0x3F; + b = (fillcolor >> 11) & 0x1F; + a = (fillcolor >> 16) & 0xFF; + break; + case V2D_COLOR_FORMAT_ARGB8565: + a = fillcolor & 0xFF; + r = (fillcolor >> 8) & 0x1F; + g = (fillcolor >> 13) & 0x3F; + b = (fillcolor >> 19) & 0x1F; + break; + case V2D_COLOR_FORMAT_BGR888: + case V2D_COLOR_FORMAT_BGRX8888: + b = fillcolor & 0xFF; + g = (fillcolor >> 8) & 0xFF; + r = (fillcolor >> 16) & 0xFF; + a = 0xFF; + break; + case V2D_COLOR_FORMAT_BGRA8888: + b = fillcolor & 0xFF; + g = (fillcolor >> 8) & 0xFF; + r = (fillcolor >> 16) & 0xFF; + a = (fillcolor >> 24) & 0xFF; + break; + case V2D_COLOR_FORMAT_ABGR8888: + a = fillcolor & 0xFF; + b = (fillcolor >> 8) & 0xFF; + g = (fillcolor >> 16) & 0xFF; + r = (fillcolor >> 24) & 0xFF; + break; + case V2D_COLOR_FORMAT_BGR565: + a = 0xFF; + b = fillcolor & 0x1F; + g = (fillcolor >> 5) & 0x3F; + r = (fillcolor >> 11) & 0x1F; + break; + case V2D_COLOR_FORMAT_BGRA5658: + b = fillcolor & 0x1F; + g = (fillcolor >> 5) & 0x3F; + r = (fillcolor >> 11) & 0x1F; + a = (fillcolor >> 16) & 0xFF; + break; + case V2D_COLOR_FORMAT_ABGR8565: + a = fillcolor & 0xFF; + b = (fillcolor >> 8) & 0x1F; + g = (fillcolor >> 13) & 0x3F; + r = (fillcolor >> 19) & 0x1F; + break; + default: + r = 0xFF; + g = 0xFF; + b = 0xFF; + a = 0xFF; + break; + } + pChl[R] = r; + pChl[G] = g; + pChl[B] = b; + pChl[A] = a; +} + +static bool do_swap(V2D_COLOR_FORMAT_E enFormatIn) +{ + switch (enFormatIn) + { + case V2D_COLOR_FORMAT_BGR888: + case V2D_COLOR_FORMAT_BGRX8888: + case V2D_COLOR_FORMAT_BGRA8888: + case V2D_COLOR_FORMAT_ABGR8888: + case V2D_COLOR_FORMAT_BGR565: + case V2D_COLOR_FORMAT_BGRA5658: + case V2D_COLOR_FORMAT_ABGR8565: + case V2D_COLOR_FORMAT_NV21: + case V2D_COLOR_FORMAT_L8_BGR565: + case V2D_COLOR_FORMAT_L8_BGR888: + case V2D_COLOR_FORMAT_L8_BGRA8888: + return RT_TRUE; + default: + return RT_FALSE; + } +} + +static bool do_narrow(V2D_CSC_MODE_E enForeCSCMode, V2D_CSC_MODE_E enBackCSCMode) +{ + int ret = RT_FALSE; + + switch (enForeCSCMode) + { + case V2D_CSC_MODE_RGB_2_BT601NARROW: + case V2D_CSC_MODE_RGB_2_BT709NARROW: + case V2D_CSC_MODE_BT601WIDE_2_BT709NARROW: + case V2D_CSC_MODE_BT601WIDE_2_BT601NARROW: + case V2D_CSC_MODE_BT601NARROW_2_BT709NARROW: + case V2D_CSC_MODE_BT709WIDE_2_BT601NARROW: + case V2D_CSC_MODE_BT709WIDE_2_BT709NARROW: + case V2D_CSC_MODE_BT709NARROW_2_BT601NARROW: + ret = RT_TRUE; + break; + default: + break; + } + switch (enBackCSCMode) + { + case V2D_CSC_MODE_RGB_2_BT601NARROW: + case V2D_CSC_MODE_RGB_2_BT709NARROW: + case V2D_CSC_MODE_BT601WIDE_2_BT709NARROW: + case V2D_CSC_MODE_BT601WIDE_2_BT601NARROW: + case V2D_CSC_MODE_BT601NARROW_2_BT709NARROW: + case V2D_CSC_MODE_BT709WIDE_2_BT601NARROW: + case V2D_CSC_MODE_BT709WIDE_2_BT709NARROW: + case V2D_CSC_MODE_BT709NARROW_2_BT601NARROW: + ret = RT_TRUE; + break; + default: + break; + } + return ret; +} + +static V2D_COLOR_FORMAT_E fmt_convert(V2D_COLOR_FORMAT_E enFormatIn) +{ + V2D_COLOR_FORMAT_E enFormatOut = 0; + + switch (enFormatIn) + { + case V2D_COLOR_FORMAT_RGB888: + case V2D_COLOR_FORMAT_RGBX8888: + case V2D_COLOR_FORMAT_RGBA8888: + case V2D_COLOR_FORMAT_ARGB8888: + case V2D_COLOR_FORMAT_RGB565: + case V2D_COLOR_FORMAT_NV12: + case V2D_COLOR_FORMAT_RGBA5658: + case V2D_COLOR_FORMAT_ARGB8565: + case V2D_COLOR_FORMAT_A8: + case V2D_COLOR_FORMAT_Y8: + enFormatOut = enFormatIn; + break; + case V2D_COLOR_FORMAT_BGR888: + case V2D_COLOR_FORMAT_BGRX8888: + case V2D_COLOR_FORMAT_BGRA8888: + case V2D_COLOR_FORMAT_ABGR8888: + case V2D_COLOR_FORMAT_BGR565: + case V2D_COLOR_FORMAT_NV21: + case V2D_COLOR_FORMAT_BGRA5658: + case V2D_COLOR_FORMAT_ABGR8565: + enFormatOut = enFormatIn - V2D_COLOR_FORMAT_BGR888; + break; + case V2D_COLOR_FORMAT_L8_RGBA8888: + case V2D_COLOR_FORMAT_L8_RGB888: + case V2D_COLOR_FORMAT_L8_RGB565: + case V2D_COLOR_FORMAT_L8_BGRA8888: + case V2D_COLOR_FORMAT_L8_BGR888: + case V2D_COLOR_FORMAT_L8_BGR565: + enFormatOut = V2D_COLOR_FORMAT_L8_RGBA8888; + break; + default: + break; + } + return enFormatOut; +} + +static int Get_L8_Palette_bytePerPixel(V2D_SURFACE_S *pstBackGround, V2D_SURFACE_S *pstForeGround) +{ + int bpp = 4; + + if (pstBackGround) + { + if (pstBackGround->format == V2D_COLOR_FORMAT_L8_RGBA8888 || pstBackGround->format == V2D_COLOR_FORMAT_L8_BGRA8888) + { + bpp = 4; + } + else if (pstBackGround->format == V2D_COLOR_FORMAT_L8_RGB888 || pstBackGround->format == V2D_COLOR_FORMAT_L8_BGR888) + { + bpp = 3; + } + else if (pstBackGround->format == V2D_COLOR_FORMAT_L8_RGB565 || pstBackGround->format == V2D_COLOR_FORMAT_L8_BGR565) + { + bpp = 2; + } + } + if (pstForeGround) + { + if (pstForeGround->format == V2D_COLOR_FORMAT_L8_RGBA8888 || pstForeGround->format == V2D_COLOR_FORMAT_L8_BGRA8888) + { + bpp = 4; + } + else if (pstForeGround->format == V2D_COLOR_FORMAT_L8_RGB888 || pstForeGround->format == V2D_COLOR_FORMAT_L8_BGR888) + { + bpp = 3; + } + else if (pstForeGround->format == V2D_COLOR_FORMAT_L8_RGB565 || pstForeGround->format == V2D_COLOR_FORMAT_L8_BGR565) + { + bpp = 2; + } + } + return bpp; +} + +static void ConfigV2dFbcDecoder(V2D_SURFACE_S *pstV2DSurface, V2D_INPUT_LAYER_E enInputLayer) +{ + v2d_fbc_decoder_bbox_reg_t bbox_x = { 0 }, bbox_y = { 0 }; + v2d_fbc_decoder_imgae_size_reg_t img_size = { 0 }; + v2d_fbc_decoder_mode_reg_t dec_mode = { 0 }; + v2d_fbc_decoder_dma_ctrl_reg_t dmac = { 0 }; + v2d_fbc_decoder_irq_ctrl_reg_t irqmask = { 0 }; + FBC_DECODER_S *pDecInfo = &pstV2DSurface->fbcDecInfo; + + LOG_D("config %s fbc decoder", (enInputLayer > 0 ? "layer1" : "layer0")); + bbox_x.field.bbox_start = pDecInfo->bboxLeft; + bbox_x.field.bbox_end = pDecInfo->bboxRight; + bbox_y.field.bbox_start = pDecInfo->bboxTop; + bbox_y.field.bbox_end = pDecInfo->bboxBottom; + img_size.field.width = pstV2DSurface->w; + img_size.field.height = pstV2DSurface->h; + dec_mode.field.mode = pDecInfo->enFbcdecMode; + dec_mode.field.format = pDecInfo->enFbcdecFmt; + dec_mode.field.is_split = pDecInfo->is_split; + dec_mode.field.rgb_pack_en = pDecInfo->rgb_pack_en; + dmac.overlay = 0xffff1a02; + irqmask.overlay = 0x00000017; + + v2d_write(V2D_LAYER_DEC_REG0_L(enInputLayer), pDecInfo->headerAddr_l); + v2d_write(V2D_LAYER_DEC_REG1_L(enInputLayer), pDecInfo->headerAddr_h); + v2d_write(V2D_LAYER_DEC_REG2_L(enInputLayer), bbox_x.overlay); + v2d_write(V2D_LAYER_DEC_REG3_L(enInputLayer), bbox_y.overlay); + v2d_write(V2D_LAYER_DEC_REG4_L(enInputLayer), img_size.overlay); + v2d_write(V2D_LAYER_DEC_REG5_L(enInputLayer), dec_mode.overlay); + v2d_write(V2D_LAYER_DEC_REG6_L(enInputLayer), dmac.overlay); + v2d_write(V2D_LAYER_DEC_REG7_L(enInputLayer), irqmask.overlay); +} + +static void ConfigV2dFbcEncoder(V2D_SURFACE_S *pstV2DSurface) +{ + v2d_fbc_encoder_bbox_reg_t bbox_x = { 0 }, bbox_y = { 0 }; + v2d_fbc_encoder_buf_size_reg_t y_buf_size = { 0 }, uv_buf_size = { 0 }; + v2d_fbc_encoder_irq_reg_t irqmask = { 0 }; + v2d_fbc_encoder_mode_reg_t enc_mode = { 0 }; + v2d_fbc_encoder_dmac_burst_reg_t dmac_burst = { 0 }; + FBC_ENCODER_S *pEncInfo = &pstV2DSurface->fbcEncInfo; + + LOG_D("config fbc encoder"); + bbox_x.field.bbox_start = pEncInfo->bboxLeft; + bbox_x.field.bbox_end = pEncInfo->bboxRight; + bbox_y.field.bbox_start = pEncInfo->bboxTop; + bbox_y.field.bbox_end = pEncInfo->bboxBottom; + y_buf_size.field.x_size = pstV2DSurface->w; + y_buf_size.field.y_size = pstV2DSurface->h; + uv_buf_size.field.x_size = pstV2DSurface->w >> 1; + uv_buf_size.field.y_size = pstV2DSurface->w >> 1; + irqmask.overlay = 0x0001ffff; + enc_mode.field.encode_enable = 1; + enc_mode.field.split_mode_en = pEncInfo->is_split; + enc_mode.field.img_pix_format = pEncInfo->enFbcencFmt; + dmac_burst.field.burst_length = 0x10; + + v2d_write(V2D_ENC_REG0, pEncInfo->headerAddr_l); + v2d_write(V2D_ENC_REG1, pEncInfo->headerAddr_h); + v2d_write(V2D_ENC_REG2, pEncInfo->payloadAddr_l); + v2d_write(V2D_ENC_REG3, pEncInfo->payloadAddr_h); + v2d_write(V2D_ENC_REG4, bbox_x.overlay); + v2d_write(V2D_ENC_REG5, bbox_y.overlay); + v2d_write(V2D_ENC_REG10, y_buf_size.overlay); + v2d_write(V2D_ENC_REG11, uv_buf_size.overlay); + v2d_write(V2D_ENC_REG13, irqmask.overlay); + v2d_write(V2D_ENC_REG15, 0x9e00ffff); + v2d_write(V2D_ENC_REG16, enc_mode.overlay); + v2d_write(V2D_ENC_REG17, dmac_burst.overlay); +} + +static void ConfigV2dInputLayer(V2D_SURFACE_S *pstV2DSurface, + V2D_AREA_S *pstV2DArea, + V2D_BLEND_CONF_S *pstBlendConf, + V2D_ROTATE_ANGLE_E enRotateAngle, + V2D_CSC_MODE_E enCSCMode, + V2D_INPUT_LAYER_E enInputLayer) +{ + const int *pCscMatrix; + V2D_SCALER_MODE_E enScaleMode = V2D_NO_SCALE; + uint32_t width = 0, height = 0; + V2D_FILLCOLOR_S *pFillColor; uint8_t chl[4]; + V2D_BLEND_LAYER_CONF_S *pBlendLayerConf; + v2d_blend_layer_ctrl0_reg_t bld_layer_ctrl0 = { 0 }; + v2d_blend_layer_ctrl1_reg_t bld_layer_ctrl1 = { 0 }; + v2d_blend_layer_ctrl2_reg_t bld_layer_ctrl2 = { 0 }; + v2d_blend_layer_ctrl3_reg_t bld_layer_ctrl3 = { 0 }; + v2d_blend_layer_factor_reg_t bld_layer_factor = { 0 }; + v2d_solid_color_ctrl0_reg_t solidcolor_ctrl0 = { 0 }; + v2d_solid_color_ctrl1_reg_t solidcolor_ctrl1 = { 0 }; + v2d_input_layer_width_height_reg_t layer_in_ori_w_h = { 0 }; + v2d_input_layer_ctrl_reg_t layer_in_ctrl = { 0 }; + v2d_input_layer_crop0_reg_t layer_in_crop0 = { 0 }; + v2d_input_layer_crop1_reg_t layer_in_crop1 = { 0 }; + v2d_input_layer_csc_ctrl0_reg_t layer_in_csc_ctrl0 = { 0 }; + v2d_input_layer_csc_ctrl1_reg_t layer_in_csc_ctrl1 = { 0 }; + v2d_input_layer_csc_ctrl2_reg_t layer_in_csc_ctrl2 = { 0 }; + v2d_input_layer_scale_mode_reg_t layer_scale_mode = { 0 }; + v2d_input_layer_scale_delta_x_reg_t layer_scale_delta_x = { 0 }; + v2d_input_layer_scale_delta_y_reg_t layer_scale_delta_y = { 0 }; + + bld_layer_ctrl1.overlay = 0; + bld_layer_ctrl3.overlay = 0; + bld_layer_factor.overlay = 0; + solidcolor_ctrl0.overlay = 0; + solidcolor_ctrl1.overlay = 0; + layer_in_ctrl.overlay = 0; + layer_in_csc_ctrl0.overlay = 0; + layer_in_csc_ctrl1.overlay = 0; + layer_in_csc_ctrl2.overlay = 0; + layer_scale_mode.overlay = 0; + layer_scale_delta_x.overlay = 0; + layer_scale_delta_y.overlay = 0; + + if ((!pstV2DSurface->solidcolor.enable) && + (pstV2DSurface->phyaddr_y_l == 0) && + (pstV2DSurface->phyaddr_y_h == 0) && + (!pstV2DSurface->fbc_enable)) + { + LOG_D("%s disable", (enInputLayer > 0 ? "layer1" : "layer0")); + bld_layer_ctrl1.field.blend_en = V2D_FUNC_DISABLE; + v2d_write(V2D_LAYER_BLD_CTRL1_LAYER(enInputLayer), bld_layer_ctrl1.overlay); + } + else + { + LOG_D("config %s rot: %d, csc: %d", (enInputLayer > 0 ? "layer1" : "layer0"), enRotateAngle, enCSCMode); + /* blendlayer */ + pBlendLayerConf = &pstBlendConf->blendlayer[enInputLayer]; + bld_layer_ctrl0.field.bld_alpha_source = pBlendLayerConf->blend_alpha_source; + bld_layer_ctrl0.field.bld_pre_alp_func = pBlendLayerConf->blend_pre_alpha_func; + bld_layer_ctrl0.field.bld_glb_alp = pBlendLayerConf->global_alpha; + bld_layer_ctrl0.field.scl_delta_y = 0; + bld_layer_ctrl1.field.blend_en = V2D_FUNC_ENABLE; + bld_layer_ctrl1.field.bld_rect_ltop_x = pBlendLayerConf->blend_area.x; + bld_layer_ctrl2.field.bld_rect_ltop_y = pBlendLayerConf->blend_area.y; + bld_layer_ctrl2.field.bld_rect_width = pBlendLayerConf->blend_area.w; + bld_layer_ctrl3.field.bld_rect_height = pBlendLayerConf->blend_area.h; + LOG_D("bld alpha_src: %d,pre_func: %d,glb_alpha: %d", pBlendLayerConf->blend_alpha_source, pBlendLayerConf->blend_pre_alpha_func, pBlendLayerConf->global_alpha); + LOG_D("bld_rect:(%d,%d,%d,%d)", pBlendLayerConf->blend_area.x, pBlendLayerConf->blend_area.y, pBlendLayerConf->blend_area.w, pBlendLayerConf->blend_area.h); + v2d_write(V2D_LAYER_BLD_CTRL0_LAYER(enInputLayer), bld_layer_ctrl0.overlay); + v2d_write(V2D_LAYER_BLD_CTRL1_LAYER(enInputLayer), bld_layer_ctrl1.overlay); + v2d_write(V2D_LAYER_BLD_CTRL2_LAYER(enInputLayer), bld_layer_ctrl2.overlay); + v2d_write(V2D_LAYER_BLD_CTRL3_LAYER(enInputLayer), bld_layer_ctrl3.overlay); + + bld_layer_factor.field.in_addr_uv_33_32 = pstV2DSurface->phyaddr_uv_h & V2D_H_ADDR_MASK; + if (pstBlendConf->blend_cmd) + { + bld_layer_factor.field.bld_color_rop2_code = pBlendLayerConf->stRop2Code.colorRop2Code; + bld_layer_factor.field.bld_alpha_rop2_code = pBlendLayerConf->stRop2Code.alphaRop2Code; + } + else + { + bld_layer_factor.field.bld_src_color_factor = pBlendLayerConf->stBlendFactor.srcColorFactor; + bld_layer_factor.field.bld_src_alpha_factor = pBlendLayerConf->stBlendFactor.srcAlphaFactor; + bld_layer_factor.field.bld_dst_color_factor = pBlendLayerConf->stBlendFactor.dstColorFactor; + bld_layer_factor.field.bld_dst_alpha_factor = pBlendLayerConf->stBlendFactor.dstAlphaFactor; + } + LOG_D("bld factor:src_c=%d,src_a=%d,dst_c=%d,dst_a=%d", pBlendLayerConf->stBlendFactor.srcColorFactor, pBlendLayerConf->stBlendFactor.srcAlphaFactor, + pBlendLayerConf->stBlendFactor.dstColorFactor, pBlendLayerConf->stBlendFactor.dstAlphaFactor); + v2d_write(V2D_LAYER_BLD_FACTOR_LAYER(enInputLayer), bld_layer_factor.overlay); + + if (pstV2DSurface->solidcolor.enable) + { + /* solid color */ + pFillColor = &pstV2DSurface->solidcolor.fillcolor; + split_fillcolor(pFillColor->colorvalue, pFillColor->format, chl); + solidcolor_ctrl0.field.solid_en = V2D_FUNC_ENABLE; + solidcolor_ctrl0.field.solid_R = chl[R]; + solidcolor_ctrl0.field.solid_G = chl[G]; + solidcolor_ctrl0.field.solid_B = chl[B]; + solidcolor_ctrl1.field.solid_A = chl[A]; + solidcolor_ctrl1.field.csc_en = V2D_FUNC_DISABLE; + v2d_write(V2D_LAYER_SOLIDCOLOR_CTRL0_LAYER(enInputLayer), solidcolor_ctrl0.overlay); + v2d_write(V2D_LAYER_SOLIDCOLOR_CTRL1_LAYER(enInputLayer), solidcolor_ctrl1.overlay); + } + else + { + /* input layer */ + solidcolor_ctrl0.field.solid_en = V2D_FUNC_DISABLE; + v2d_write(V2D_LAYER_SOLIDCOLOR_CTRL0_LAYER(enInputLayer), solidcolor_ctrl0.overlay); + if (pstV2DSurface->fbc_enable) + { + ConfigV2dFbcDecoder(pstV2DSurface, enInputLayer); + } + else + { + v2d_write(V2D_LAYER_Y_ADDR_L_LAYER(enInputLayer), pstV2DSurface->phyaddr_y_l); + v2d_write(V2D_LAYER_Y_ADDR_H_LAYER(enInputLayer), pstV2DSurface->phyaddr_y_h); + v2d_write(V2D_LAYER_UV_ADDR_L_LAYER(enInputLayer), pstV2DSurface->phyaddr_uv_l); + } + layer_in_ori_w_h.field.layer_in_ori_width = pstV2DSurface->w; + layer_in_ori_w_h.field.layer_in_ori_height = pstV2DSurface->h; + v2d_write(V2D_LAYER_WIDTH_HEIGHT_LAYER(enInputLayer), layer_in_ori_w_h.overlay); + + layer_in_ctrl.field.stride = pstV2DSurface->stride; + layer_in_ctrl.field.swap = do_swap(pstV2DSurface->format); + layer_in_ctrl.field.format = fmt_convert(pstV2DSurface->format); + layer_in_ctrl.field.rotation = enRotateAngle; + layer_in_ctrl.field.fbc_en = pstV2DSurface->fbc_enable; + v2d_write(V2D_LAYER_CTRL_LAYER(enInputLayer), layer_in_ctrl.overlay); + /* crop */ + layer_in_crop0.field.layer_in_crop_ltop_x = pstV2DArea->x; + layer_in_crop0.field.layer_in_crop_ltop_y = pstV2DArea->y; + layer_in_crop1.field.layer_in_crop_width = pstV2DArea->w; + layer_in_crop1.field.layer_in_crop_height = pstV2DArea->h; + LOG_D("crop:(%d,%d,%d,%d)", pstV2DArea->x, pstV2DArea->y, pstV2DArea->w, pstV2DArea->h); + v2d_write(V2D_LAYER_CROP_REG0_LAYER(enInputLayer), layer_in_crop0.overlay); + v2d_write(V2D_LAYER_CROP_REG1_LAYER(enInputLayer), layer_in_crop1.overlay); + /* csc */ + if (enCSCMode < V2D_CSC_MODE_BUTT) + { + layer_in_csc_ctrl0.field.csc_en = V2D_FUNC_ENABLE; + pCscMatrix = &cscmatrix[enCSCMode][0][0]; + layer_in_csc_ctrl0.field.csc_matrix0 = pCscMatrix[0]; + for (int i = 0; i < 5; i++) + { + layer_in_csc_ctrl1.field.csc_matrix1 = pCscMatrix[2 * i + 1]; + layer_in_csc_ctrl1.field.csc_matrix2 = pCscMatrix[2 * i + 2]; + v2d_write(V2D_LAYER_CSC_CRTL1_LAYER(enInputLayer) + 0x4 * i, layer_in_csc_ctrl1.overlay); + } + layer_in_csc_ctrl2.field.csc_matrix11 = pCscMatrix[11]; + v2d_write(V2D_LAYER_CSC_CRTL6_LAYER(enInputLayer), layer_in_csc_ctrl2.overlay); + } + else + { + layer_in_csc_ctrl0.field.csc_en = V2D_FUNC_DISABLE; + } + v2d_write(V2D_LAYER_CSC_CRTL0_LAYER(enInputLayer), layer_in_csc_ctrl0.overlay); + /* scale */ + if (enRotateAngle == V2D_ROT_90 || enRotateAngle == V2D_ROT_270) + { + width = pstV2DArea->h; height = pstV2DArea->w; + } + else + { + width = pstV2DArea->w; height = pstV2DArea->h; + } + if (width == pBlendLayerConf->blend_area.w && height == pBlendLayerConf->blend_area.h) + { + enScaleMode = V2D_NO_SCALE; + } + else if (width > pBlendLayerConf->blend_area.w || height > pBlendLayerConf->blend_area.h) + { + enScaleMode = V2D_SCALE_DOWN; + } + else if (width < pBlendLayerConf->blend_area.w || height < pBlendLayerConf->blend_area.h) + { + enScaleMode = V2D_SCALE_UP; + } + LOG_D("scale: %d", enScaleMode); + layer_scale_mode.overlay = layer_in_csc_ctrl2.overlay; + layer_scale_mode.field.scl_mode = enScaleMode; + v2d_write(V2D_LAYER_SCALE_MODE_LAYER(enInputLayer), layer_scale_mode.overlay); + if (enScaleMode) + { + layer_scale_delta_x.field.scl_delta_x = (width << 16) / pBlendLayerConf->blend_area.w; + layer_scale_delta_y.overlay = bld_layer_ctrl0.overlay; + layer_scale_delta_y.field.scl_delta_y = (height << 16) / pBlendLayerConf->blend_area.h; + v2d_write(V2D_LAYER_SCALE_DELTA_X_LAYER(enInputLayer), layer_scale_delta_x.overlay); + v2d_write(V2D_LAYER_SCALE_DELTA_Y_LAYER(enInputLayer), layer_scale_delta_y.overlay); + } + else + { + layer_scale_delta_x.field.scl_delta_x = (1 << 16); + layer_scale_delta_y.overlay = bld_layer_ctrl0.overlay; + layer_scale_delta_y.field.scl_delta_y = (1 << 16); + v2d_write(V2D_LAYER_SCALE_DELTA_X_LAYER(enInputLayer), layer_scale_delta_x.overlay); + v2d_write(V2D_LAYER_SCALE_DELTA_Y_LAYER(enInputLayer), layer_scale_delta_y.overlay); + } + } + } +} + +static void ConfigV2dMaskLayer(V2D_SURFACE_S *pstMask, V2D_AREA_S *pstMaskRect, V2D_BLEND_CONF_S *pstBlendConf) +{ + v2d_mask_width_reg_t mask_in_width = { 0 }; + v2d_mask_height_reg_t mask_in_height = { 0 }; + v2d_mask_crop0_reg_t mask_in_crop0 = { 0 }; + v2d_mask_crop1_reg_t mask_in_crop1 = { 0 }; + v2d_blend_mask_ctrl0_reg_t bld_mask_ctrl0 = { 0 }; + v2d_blend_mask_ctrl1_reg_t bld_mask_ctrl1 = { 0 }; + v2d_blend_mask_ctrl2_reg_t bld_mask_ctrl2 = { 0 }; + + bld_mask_ctrl0.overlay = 0; + mask_in_width.overlay = 0; + bld_mask_ctrl2.overlay = 0; + + if (pstMask->phyaddr_y_l != 0 || pstMask->phyaddr_y_h != 0) + { + LOG_D("ConfigV2dMaskLayer"); + mask_in_width.field.mask_addr_33_32 = (pstMask->phyaddr_y_h & V2D_H_ADDR_MASK); + mask_in_width.field.mask_ori_width = pstMask->w; + mask_in_height.field.mask_ori_height = pstMask->h; + mask_in_height.field.mask_ori_stride = pstMask->stride; + mask_in_crop0.field.mask_crop_ltop_x = pstMaskRect->x; + mask_in_crop0.field.mask_crop_ltop_y = pstMaskRect->y; + mask_in_crop1.field.mask_crop_width = pstMaskRect->w; + mask_in_crop1.field.mask_crop_height = pstMaskRect->h; + bld_mask_ctrl0.field.bld_mask_enable = pstBlendConf->mask_cmd; + bld_mask_ctrl0.field.bld_mask_rect_ltop_x = pstBlendConf->blend_mask_area.x; + bld_mask_ctrl1.field.bld_mask_rect_ltop_y = pstBlendConf->blend_mask_area.y; + bld_mask_ctrl1.field.bld_mask_rect_width = pstBlendConf->blend_mask_area.w; + bld_mask_ctrl2.field.bld_mask_rect_height = pstBlendConf->blend_mask_area.h; + v2d_write(V2D_MASK_ADDR_L, pstMask->phyaddr_y_l); + v2d_write(V2D_MASK_WIDTH, mask_in_width.overlay); + v2d_write(V2D_MASK_HEIGHT, mask_in_height.overlay); + v2d_write(V2D_MASK_CROP_REG0, mask_in_crop0.overlay); + v2d_write(V2D_MASK_CROP_REG1, mask_in_crop1.overlay); + v2d_write(V2D_BLD_MASK_REG0, bld_mask_ctrl0.overlay); + v2d_write(V2D_BLD_MASK_REG1, bld_mask_ctrl1.overlay); + v2d_write(V2D_BLD_MASK_REG2, bld_mask_ctrl2.overlay); + } + else + { + LOG_D("mask layer disable"); + bld_mask_ctrl0.field.bld_mask_enable = V2D_FUNC_DISABLE; + v2d_write(V2D_BLD_MASK_REG0, bld_mask_ctrl0.overlay); + } +} + +static void ConfigPaletteTable(V2D_SURFACE_S *pstBackGround, V2D_SURFACE_S *pstForeGround, V2D_PALETTE_S *pstPalette) +{ + int bpp; + uint32_t val; + uint8_t *pTmp, r, g, b, a; + + if (pstPalette->len != 0) + { + LOG_D("ConfigPaletteTable"); + pTmp = pstPalette->palVal; + bpp = Get_L8_Palette_bytePerPixel(pstBackGround, pstForeGround); + LOG_D("bpp: %d, palette len: %d", bpp, pstPalette->len); + for (int i = 0; i < (pstPalette->len / bpp); i++) + { + if (bpp == 4) + { + r = *(pTmp + 4 * i); g = *(pTmp + 4 * i + 1); + b = *(pTmp + 4 * i + 2); a = *(pTmp + 4 * i + 3); + } + else if (bpp == 3) + { + r = *(pTmp + 3 * i); g = *(pTmp + 3 * i + 1); + b = *(pTmp + 3 * i + 2); a = 0xFF; + } + else if (bpp == 2) + { + r = *(pTmp + 2 * i) & 0x1F; + g = ((*(pTmp + 2 * i) >> 5) & 0x7) | ((*(pTmp + 2 * i + 1) & 0x7) << 3); + b = (*(pTmp + 2 * i + 1) >> 3) & 0x1F; + a = 0xFF; + } + val = r | (g << 8) | (b << 16) | (a << 24); + v2d_write(V2D_PALETTE_TABLE(i), val); + } + } +} + +static void ConfigV2dBlendMode_And_BgColor(V2D_BLEND_CONF_S *pstBlendConf) +{ + V2D_FILLCOLOR_S *pFillColor; + uint8_t chl[4]; + v2d_blend_ctrl0_reg_t blend_ctrl0 = { 0 }; + v2d_blend_ctrl1_reg_t blend_ctrl1 = { 0 }; + + LOG_D("ConfigV2dBlendMode_And_BgColor"); + blend_ctrl0.overlay = 0; + blend_ctrl1.overlay = 0; + blend_ctrl0.field.bld_mode = pstBlendConf->blend_cmd; + blend_ctrl0.field.bld_bg_enable = pstBlendConf->bgcolor.enable; + pFillColor = &pstBlendConf->bgcolor.fillcolor; + split_fillcolor(pFillColor->colorvalue, V2D_COLOR_FORMAT_RGBA8888, chl); + LOG_D("bgcolor_en: %d,r: %d,g: %d,b: %d,alpha: %d", pstBlendConf->bgcolor.enable, chl[R], chl[G], chl[B], chl[A]); + blend_ctrl0.field.bld_bg_r = chl[R]; + blend_ctrl0.field.bld_bg_g = chl[G]; + blend_ctrl0.field.bld_bg_b = chl[B]; + blend_ctrl1.field.bld_bg_a = chl[A]; + v2d_write(V2D_BLEND_REG0, blend_ctrl0.overlay); + v2d_write(V2D_BLEND_REG1, blend_ctrl1.overlay); +} + +static void ConfigV2dOutput(V2D_SURFACE_S *pstDst, + V2D_AREA_S *pstDstRect, + V2D_CSC_MODE_E enForeCSCMode, + V2D_CSC_MODE_E enBackCSCMode, + V2D_DITHER_E dither) +{ + v2d_output_width_reg_t output_width = { 0 }; + v2d_output_height_reg_t output_height = { 0 }; + v2d_output_ctrl0_reg_t output_ctrl0 = { 0 }; + v2d_output_ctrl1_reg_t output_ctrl1 = { 0 }; + v2d_output_ctrl2_reg_t output_ctrl2 = { 0 }; + + LOG_D("config output"); + output_width.overlay = 0; + output_ctrl0.overlay = 0; + output_ctrl2.overlay = 0; + output_width.field.out_ori_width = pstDst->w; + output_width.field.out_addr_uv_33_32 = (pstDst->phyaddr_uv_h & V2D_H_ADDR_MASK); + output_height.field.out_ori_height = pstDst->h; + output_height.field.out_ori_stride = pstDst->stride; + output_ctrl0.field.format = fmt_convert(pstDst->format); + output_ctrl0.field.range = do_narrow(enForeCSCMode, enBackCSCMode); + output_ctrl0.field.dither = dither; + output_ctrl0.field.swap = do_swap(pstDst->format); + output_ctrl0.field.fbc_en = pstDst->fbc_enable; + output_ctrl0.field.crop_ltop_x = pstDstRect->x; + output_ctrl1.field.crop_ltop_y = pstDstRect->y; + output_ctrl1.field.crop_width = pstDstRect->w; + output_ctrl2.field.crop_height = pstDstRect->h; + LOG_D("dst:w=%d,h=%d", pstDst->w, pstDst->h); + LOG_D("crop=(%d,%d,%d,%d)", pstDstRect->x, pstDstRect->y, pstDstRect->w, pstDstRect->h); + LOG_D("dst:fmt=%d, dither: %d,narrow=%d, swap=%d, stride=%d", + output_ctrl0.field.format, output_ctrl0.field.dither, output_ctrl0.field.range, output_ctrl0.field.swap, pstDst->stride); + + v2d_write(V2D_OUTPUT_WIDTH, output_width.overlay); + v2d_write(V2D_OUTPUT_HEIGHT, output_height.overlay); + v2d_write(V2D_OUTPUT_CRTL0, output_ctrl0.overlay); + v2d_write(V2D_OUTPUT_CRTL1, output_ctrl1.overlay); + v2d_write(V2D_OUTPUT_CRTL2, output_ctrl2.overlay); + if (pstDst->fbc_enable) + { + ConfigV2dFbcEncoder(pstDst); + } + else + { + v2d_write(V2D_OUTPUT_Y_ADDR_L, pstDst->phyaddr_y_l); + v2d_write(V2D_OUTPUT_Y_ADDR_H, pstDst->phyaddr_y_h); + v2d_write(V2D_OUTPUT_UV_ADDR_L, pstDst->phyaddr_uv_l); + } +} + +static void ConfigV2dDmac(void) +{ + v2d_dma_ctrl_reg_t dma_ctrl; + + dma_ctrl.overlay = 0; + dma_ctrl.field.dmac_arb_mode = 2; + dma_ctrl.field.dmac_max_req_num = 7; + dma_ctrl.field.dmac_postwr_en = 255; + dma_ctrl.field.dmac_rst_n_pwr = 1; + dma_ctrl.field.dmac_arqos = 2; + dma_ctrl.field.dmac_awqos = 2; + v2d_write(V2D_DMA_CTRL, dma_ctrl.overlay); +} + +static void TriggerV2dRun(V2D_PARAM_S *pParam) +{ + v2d_ctrl_reg_t ctrl = { 0 }; + v2d_fbc_decoder_trigger_reg_t decTrigger = { 0 }; + v2d_fbc_encoder_trigger_reg_t encTrigger = { 0 }; + + if (pParam->layer0.fbc_enable) + { + decTrigger.overlay = 0; + decTrigger.field.direct_swap = 1; + v2d_write(V2D_L0_DEC_REG10, decTrigger.overlay); + } + if (pParam->layer1.fbc_enable) + { + decTrigger.overlay = 0; + decTrigger.field.direct_swap = 1; + v2d_write(V2D_L1_DEC_REG10, decTrigger.overlay); + } + if (pParam->dst.fbc_enable) + { + encTrigger.overlay = 0; + encTrigger.field.direct_swap = 1; + v2d_write(V2D_ENC_REG12, encTrigger.overlay); + } + ctrl.overlay = 0; + ctrl.field.rdma_burst_len = 4; + ctrl.field.wdma_burst_len = 16; + ctrl.field.trigger = 1; + rt_hw_dsb(); + v2d_write(V2D_CTRL_REG, ctrl.overlay); +} + +void config_v2d_hw(V2D_SUBMIT_TASK_S *pTask) +{ + V2D_SURFACE_S *pstBackGround, *pstForeGround, *pstMask, *pstDst; + V2D_AREA_S *pstBackGroundRect, *pstForeGroundRect, *pstMaskRect, *pstDstRect; + V2D_BLEND_CONF_S *pstBlendConf; + V2D_ROTATE_ANGLE_E enForeRoate, enBackRotate; + V2D_CSC_MODE_E enForeCscMode, enBackCscMode; + V2D_PALETTE_S *pstPalette; + V2D_DITHER_E enDither; + V2D_PARAM_S *pV2dParam; + + pV2dParam = &pTask->param; + pstBackGround = &pV2dParam->layer0; + pstBackGroundRect = &pV2dParam->l0_rect; + pstForeGround = &pV2dParam->layer1; + pstForeGroundRect = &pV2dParam->l1_rect; + pstMask = &pV2dParam->mask; + pstMaskRect = &pV2dParam->mask_rect; + pstDst = &pV2dParam->dst; + pstDstRect = &pV2dParam->dst_rect; + pstBlendConf = &pV2dParam->blendconf; + enBackRotate = pV2dParam->l0_rt; + enForeRoate = pV2dParam->l1_rt; + enBackCscMode = pV2dParam->l0_csc; + enForeCscMode = pV2dParam->l1_csc; + enDither = pV2dParam->dither; + pstPalette = &pV2dParam->palette; + + /* init scaler coef */ + v2d_scaler_coef_init(); + /* config layer0 */ + ConfigV2dInputLayer(pstBackGround, pstBackGroundRect, pstBlendConf, enBackRotate, enBackCscMode, V2D_INPUT_LAYER0); + /* config layer1 */ + ConfigV2dInputLayer(pstForeGround, pstForeGroundRect, pstBlendConf, enForeRoate, enForeCscMode, V2D_INPUT_LAYER1); + /* set palette */ + ConfigPaletteTable(pstBackGround, pstForeGround, pstPalette); + /* config mask */ + ConfigV2dMaskLayer(pstMask, pstMaskRect, pstBlendConf); + /* blend */ + ConfigV2dBlendMode_And_BgColor(pstBlendConf); + /* output */ + ConfigV2dOutput(pstDst, pstDstRect, enForeCscMode, enBackCscMode, enDither); + /* DMA control */ + ConfigV2dDmac(); + /* set v2d qos */ + ConfigAxiBus(); + /* trigger */ + TriggerV2dRun(pV2dParam); + LOG_D("v2d config done"); +} diff --git a/bsp/spacemit/dm/soc/v2d/v2d_internal.h b/bsp/spacemit/dm/soc/v2d/v2d_internal.h new file mode 100644 index 000000000000..e3f1916bbc72 --- /dev/null +++ b/bsp/spacemit/dm/soc/v2d/v2d_internal.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __SPACEMIT_V2D_INTERNAL_H__ +#define __SPACEMIT_V2D_INTERNAL_H__ + +#include +#include +#include + +#include + +#define DBG_TAG "soc.spacemit.v2d" +#define DBG_LVL DBG_INFO +#include + +void v2d_hw_set_base(void *base); +int v2d_global_reset(void); +uint32_t v2d_irq_status(void); +uint32_t v2d_irqerr_status(void); +void v2d_dump_irqraw_status(void); +void v2d_irq_clear(uint32_t irq_status); +void v2d_irqerr_clear(uint32_t irq_error); +void v2d_irq_enable(void); +void v2d_irq_disable(void); +void config_v2d_hw(V2D_SUBMIT_TASK_S *task); + +#endif /* __SPACEMIT_V2D_INTERNAL_H__ */ diff --git a/bsp/spacemit/dm/soc/v2d/v2d_reg.h b/bsp/spacemit/dm/soc/v2d/v2d_reg.h new file mode 100644 index 000000000000..c36bca0cf026 --- /dev/null +++ b/bsp/spacemit/dm/soc/v2d/v2d_reg.h @@ -0,0 +1,922 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __SPACEMIT_V2D_REG_H__ +#define __SPACEMIT_V2D_REG_H__ + +#define V2D_REG_BASE 0xC0100000 +#define PMUA_REG_BASE 0xd4282800 +#define V2D_TOP_BASE 0x000 +#define V2D_CORE_BASE 0x100 +#define V2D_ENC_BASE 0x800 +#define V2D_L0_DEC_BASE 0x900 +#define V2D_L1_DEC_BASE 0xa00 + +/* v2d clk offset */ +#define V2D_CLK_RES_CTRL0 0x44 +#define V2D_CLK_RES_CTRL1 0x4c + +/* v2d top offset */ +#define V2D_AUTO_CLK_REG (0x00 + V2D_TOP_BASE) +#define V2D_ERR_IRQ_MASK (0x04 + V2D_TOP_BASE) +#define V2D_IRQ_MASK (0x08 + V2D_TOP_BASE) +#define V2D_ERR_IRQ_STATUS (0x0C + V2D_TOP_BASE) +#define V2D_IRQ_STATUS (0x10 + V2D_TOP_BASE) +#define V2D_ERR_IRQ_RAW (0x14 + V2D_TOP_BASE) +#define V2D_IRQ_RAW (0x18 + V2D_TOP_BASE) +#define V2D_AXI_BUS_CTRL (0x1C + V2D_TOP_BASE) + +#define V2D_GLOBAL_RESET RT_BIT(8) +#define V2D_AUTO_CLK_EN RT_BIT(9) +#define V2D_ENC_AUTO_CLK_EN RT_BIT(10) +#define V2D_TOP_AUTO_CLK_EN RT_BIT(11) +#define V2D_EOF_IRQ_STATUS RT_BIT(0) +#define V2D_FBCENC_IRQ_STATUS RT_BIT(1) +#define V2D_EOF_IRQ_MASK RT_BIT(0) +#define V2D_FBCENC_IRQ_MASK RT_BIT(1) + +#define V2D_H_ADDR_MASK 0x3 +/* v2d core offset */ +#define V2D_CTRL_REG (0x00 + V2D_CORE_BASE) +#define V2D_SCALER_COEF_REG0 (0x04 + V2D_CORE_BASE) +#define V2D_SCALER_COEF_RGG1 (0x08 + V2D_CORE_BASE) +#define V2D_SCALER_COEF_REG2 (0x0C + V2D_CORE_BASE) +#define V2D_SCALER_COEF_RGG3 (0x10 + V2D_CORE_BASE) +#define V2D_SCALER_COEF_REG4 (0x14 + V2D_CORE_BASE) +#define V2D_SCALER_COEF_RGG5 (0x18 + V2D_CORE_BASE) +#define V2D_SCALER_COEF_REG6 (0x1C + V2D_CORE_BASE) +#define V2D_SCALER_COEF_RGG7 (0x20 + V2D_CORE_BASE) +#define V2D_SCALER_COEF_REG8 (0x24 + V2D_CORE_BASE) +#define V2D_SCALER_COEF_RGG9 (0x28 + V2D_CORE_BASE) +#define V2D_SCALER_COEF_REG10 (0x2C + V2D_CORE_BASE) +#define V2D_SCALER_COEF_RGG11 (0x30 + V2D_CORE_BASE) +#define V2D_SCALER_COEF_REG12 (0x34 + V2D_CORE_BASE) +#define V2D_SCALER_COEF_RGG13 (0x38 + V2D_CORE_BASE) +#define V2D_SCALER_COEF_REG14 (0x3C + V2D_CORE_BASE) +#define V2D_SCALER_COEF_RGG15 (0x40 + V2D_CORE_BASE) +#define V2D_SCALER_COEF_REG16 (0x44 + V2D_CORE_BASE) +#define V2D_SCALER_COEF_RGG17 (0x48 + V2D_CORE_BASE) +#define V2D_SCALER_COEF_REG18 (0x4C + V2D_CORE_BASE) +#define V2D_SCALER_COEF_RGG19 (0x50 + V2D_CORE_BASE) +#define V2D_SCALER_COEF_REG20 (0x54 + V2D_CORE_BASE) +#define V2D_SCALER_COEF_RGG21 (0x58 + V2D_CORE_BASE) +#define V2D_SCALER_COEF_REG22 (0x5C + V2D_CORE_BASE) +#define V2D_SCALER_COEF_RGG23 (0x60 + V2D_CORE_BASE) +#define V2D_SCALER_COEF_REG(i) (0x04 * (i + 1) + V2D_CORE_BASE) +#define SCALER_COEF_REG_NUM 24 + +#define V2D_BLEND_REG0 (0x64 + V2D_CORE_BASE) +#define V2D_BLEND_REG1 (0x68 + V2D_CORE_BASE) +#define V2D_BLD_MASK_REG0 (0x6C + V2D_CORE_BASE) +#define V2D_BLD_MASK_REG1 (0x70 + V2D_CORE_BASE) +#define V2D_BLD_MASK_REG2 (0x74 + V2D_CORE_BASE) + +#define V2D_OUTPUT_Y_ADDR_L (0x78 + V2D_CORE_BASE) +#define V2D_OUTPUT_Y_ADDR_H (0x7C + V2D_CORE_BASE) +#define V2D_OUTPUT_UV_ADDR_L (0x80 + V2D_CORE_BASE) +#define V2D_OUTPUT_UV_ADDR_H (0x84 + V2D_CORE_BASE) +#define V2D_OUTPUT_WIDTH (0x84 + V2D_CORE_BASE) +#define V2D_OUTPUT_HEIGHT (0x88 + V2D_CORE_BASE) +#define V2D_OUTPUT_CRTL0 (0x8C + V2D_CORE_BASE) +#define V2D_OUTPUT_CRTL1 (0x90 + V2D_CORE_BASE) +#define V2D_OUTPUT_CRTL2 (0x94 + V2D_CORE_BASE) + +#define V2D_MASK_ADDR_L (0x98 + V2D_CORE_BASE) +#define V2D_MASK_ADDR_H (0x9C + V2D_CORE_BASE) +#define V2D_MASK_WIDTH (0x9C + V2D_CORE_BASE) +#define V2D_MASK_HEIGHT (0xA0 + V2D_CORE_BASE) +#define V2D_MASK_CROP_REG0 (0xA4 + V2D_CORE_BASE) +#define V2D_MASK_CROP_REG1 (0xA8 + V2D_CORE_BASE) + +#define V2D_LAYER0_Y_ADDR_L (0xAC + V2D_CORE_BASE) +#define V2D_LAYER0_Y_ADDR_H (0xB0 + V2D_CORE_BASE) +#define V2D_LAYER0_UV_ADDR_L (0xB4 + V2D_CORE_BASE) +#define V2D_LAYER0_UV_ADDR_H (0xB8 + V2D_CORE_BASE) +#define V2D_LAYER0_BLD_FACTOR (0xB8 + V2D_CORE_BASE) +#define V2D_LAYER0_WIDTH_HEIGHT (0xBC + V2D_CORE_BASE) +#define V2D_LAYER0_CTRL (0xC0 + V2D_CORE_BASE) +#define V2D_LAYER0_CROP_REG0 (0xC4 + V2D_CORE_BASE) +#define V2D_LAYER0_CROP_REG1 (0xC8 + V2D_CORE_BASE) +#define V2D_LAYER0_SOLIDCOLOR_CTRL0 (0xCC + V2D_CORE_BASE) +#define V2D_LAYER0_SOLIDCOLOR_CTRL1 (0xD0 + V2D_CORE_BASE) +#define V2D_LAYER0_CSC_CRTL0 (0xD0 + V2D_CORE_BASE) +#define V2D_LAYER0_CSC_CRTL1 (0xD4 + V2D_CORE_BASE) +#define V2D_LAYER0_CSC_CRTL2 (0xD8 + V2D_CORE_BASE) +#define V2D_LAYER0_CSC_CRTL3 (0xDC + V2D_CORE_BASE) +#define V2D_LAYER0_CSC_CRTL4 (0xE0 + V2D_CORE_BASE) +#define V2D_LAYER0_CSC_CRTL5 (0xE4 + V2D_CORE_BASE) +#define V2D_LAYER0_CSC_CRTL6 (0xE8 + V2D_CORE_BASE) +#define V2D_LAYER0_SCALE_MODE (0xE8 + V2D_CORE_BASE) +#define V2D_LAYER0_SCALE_DELTA_X (0xEC + V2D_CORE_BASE) +#define V2D_LAYER0_SCALE_DELTA_Y (0xF0 + V2D_CORE_BASE) +#define V2D_LAYER0_BLD_CTRL0 (0xF0 + V2D_CORE_BASE) +#define V2D_LAYER0_BLD_CTRL1 (0xF4 + V2D_CORE_BASE) +#define V2D_LAYER0_BLD_CTRL2 (0xF8 + V2D_CORE_BASE) +#define V2D_LAYER0_BLD_CTRL3 (0xFC + V2D_CORE_BASE) + +#define V2D_LAYER1_Y_ADDR_L (0x100 + V2D_CORE_BASE) +#define V2D_LAYER1_Y_ADDR_H (0x104 + V2D_CORE_BASE) +#define V2D_LAYER1_UV_ADDR_L (0x108 + V2D_CORE_BASE) +#define V2D_LAYER1_UV_ADDR_H (0x10C + V2D_CORE_BASE) +#define V2D_LAYER1_BLD_FACTOR (0x10C + V2D_CORE_BASE) +#define V2D_LAYER1_WIDTH_HEIGHT (0x110 + V2D_CORE_BASE) +#define V2D_LAYER1_CTRL (0x114 + V2D_CORE_BASE) +#define V2D_LAYER1_CROP_REG0 (0x118 + V2D_CORE_BASE) +#define V2D_LAYER1_CROP_REG1 (0x11C + V2D_CORE_BASE) +#define V2D_LAYER1_SOLIDCOLOR_CTRL0 (0x120 + V2D_CORE_BASE) +#define V2D_LAYER1_SOLIDCOLOR_CTRL1 (0x124 + V2D_CORE_BASE) +#define V2D_LAYER1_CSC_CRTL0 (0x124 + V2D_CORE_BASE) +#define V2D_LAYER1_CSC_CRTL1 (0x128 + V2D_CORE_BASE) +#define V2D_LAYER1_CSC_CRTL2 (0x12C + V2D_CORE_BASE) +#define V2D_LAYER1_CSC_CRTL3 (0x130 + V2D_CORE_BASE) +#define V2D_LAYER1_CSC_CRTL4 (0x134 + V2D_CORE_BASE) +#define V2D_LAYER1_CSC_CRTL5 (0x138 + V2D_CORE_BASE) +#define V2D_LAYER1_CSC_CRTL6 (0x13C + V2D_CORE_BASE) +#define V2D_LAYER1_SCALE_MODE (0x13C + V2D_CORE_BASE) +#define V2D_LAYER1_SCALE_DELTA_X (0x140 + V2D_CORE_BASE) +#define V2D_LAYER1_SCALE_DELTA_Y (0x144 + V2D_CORE_BASE) +#define V2D_LAYER1_BLD_CTRL0 (0x144 + V2D_CORE_BASE) +#define V2D_LAYER1_BLD_CTRL1 (0x148 + V2D_CORE_BASE) +#define V2D_LAYER1_BLD_CTRL2 (0x14C + V2D_CORE_BASE) +#define V2D_LAYER1_BLD_CTRL3 (0x150 + V2D_CORE_BASE) + +#define V2D_LAYER_Y_ADDR_L_LAYER(i) (0xAC + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_Y_ADDR_H_LAYER(i) (0xB0 + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_UV_ADDR_L_LAYER(i) (0xB4 + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_UV_ADDR_H_LAYER(i) (0xB8 + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_BLD_FACTOR_LAYER(i) (0xB8 + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_WIDTH_HEIGHT_LAYER(i) (0xBC + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_CTRL_LAYER(i) (0xC0 + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_CROP_REG0_LAYER(i) (0xC4 + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_CROP_REG1_LAYER(i) (0xC8 + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_SOLIDCOLOR_CTRL0_LAYER(i) (0xCC + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_SOLIDCOLOR_CTRL1_LAYER(i) (0xD0 + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_CSC_CRTL0_LAYER(i) (0xD0 + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_CSC_CRTL1_LAYER(i) (0xD4 + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_CSC_CRTL2_LAYER(i) (0xD8 + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_CSC_CRTL3_LAYER(i) (0xDC + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_CSC_CRTL4_LAYER(i) (0xE0 + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_CSC_CRTL5_LAYER(i) (0xE4 + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_CSC_CRTL6_LAYER(i) (0xE8 + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_SCALE_MODE_LAYER(i) (0xE8 + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_SCALE_DELTA_X_LAYER(i) (0xEC + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_SCALE_DELTA_Y_LAYER(i) (0xF0 + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_BLD_CTRL0_LAYER(i) (0xF0 + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_BLD_CTRL1_LAYER(i) (0xF4 + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_BLD_CTRL2_LAYER(i) (0xF8 + i * 0x54 + V2D_CORE_BASE) +#define V2D_LAYER_BLD_CTRL3_LAYER(i) (0xFC + i * 0x54 + V2D_CORE_BASE) + +#define V2D_DEBUG_REG0 (0x1FC + V2D_CORE_BASE) +#define V2D_DEBUG_REG1 (0x200 + V2D_CORE_BASE) +#define V2D_DMA_CTRL (0x204 + V2D_CORE_BASE) +#define V2D_PALETTE_TABLE(i) (0x208 + i * 0x4 + V2D_CORE_BASE) + +#define V2D_L0_DEC_REG0 (V2D_L0_DEC_BASE + 0x000) /* register hdr_base_addr_low */ +#define V2D_L0_DEC_REG1 (V2D_L0_DEC_BASE + 0x004) /* register hdr_base_addr_high */ +#define V2D_L0_DEC_REG2 (V2D_L0_DEC_BASE + 0x008) /* register bbox_coor_x */ +#define V2D_L0_DEC_REG3 (V2D_L0_DEC_BASE + 0x00c) /* register bbox_coor_y */ +#define V2D_L0_DEC_REG4 (V2D_L0_DEC_BASE + 0x010) /* register image_size */ +#define V2D_L0_DEC_REG5 (V2D_L0_DEC_BASE + 0x014) /* register dec_mode */ +#define V2D_L0_DEC_REG6 (V2D_L0_DEC_BASE + 0x018) /* register dmac_ctrl */ +#define V2D_L0_DEC_REG7 (V2D_L0_DEC_BASE + 0x01c) /* register irq_mask */ +#define V2D_L0_DEC_REG8 (V2D_L0_DEC_BASE + 0x020) /* register irq_raw */ +#define V2D_L0_DEC_REG9 (V2D_L0_DEC_BASE + 0x024) /* register irq_status */ +#define V2D_L0_DEC_REG10 (V2D_L0_DEC_BASE + 0x028) /* register trig_ctrl */ +#define V2D_L0_DEC_REG11 (V2D_L0_DEC_BASE + 0x02c) /* register output_ybase */ +#define V2D_L0_DEC_REG12 (V2D_L0_DEC_BASE + 0x030) /* register output_cbase */ +#define V2D_L0_DEC_REG13 (V2D_L0_DEC_BASE + 0x034) /* register output_stride */ + +#define V2D_L1_DEC_REG0 (V2D_L1_DEC_BASE + 0x000) +#define V2D_L1_DEC_REG1 (V2D_L1_DEC_BASE + 0x004) +#define V2D_L1_DEC_REG2 (V2D_L1_DEC_BASE + 0x008) +#define V2D_L1_DEC_REG3 (V2D_L1_DEC_BASE + 0x00c) +#define V2D_L1_DEC_REG4 (V2D_L1_DEC_BASE + 0x010) +#define V2D_L1_DEC_REG5 (V2D_L1_DEC_BASE + 0x014) +#define V2D_L1_DEC_REG6 (V2D_L1_DEC_BASE + 0x018) +#define V2D_L1_DEC_REG7 (V2D_L1_DEC_BASE + 0x01c) +#define V2D_L1_DEC_REG8 (V2D_L1_DEC_BASE + 0x020) +#define V2D_L1_DEC_REG9 (V2D_L1_DEC_BASE + 0x024) +#define V2D_L1_DEC_REG10 (V2D_L1_DEC_BASE + 0x028) +#define V2D_L1_DEC_REG11 (V2D_L1_DEC_BASE + 0x02c) +#define V2D_L1_DEC_REG12 (V2D_L1_DEC_BASE + 0x030) +#define V2D_L1_DEC_REG13 (V2D_L1_DEC_BASE + 0x034) + +#define V2D_LAYER_DEC_REG0_L(i) (V2D_L0_DEC_BASE + i * 0x100 + 0x000) +#define V2D_LAYER_DEC_REG1_L(i) (V2D_L0_DEC_BASE + i * 0x100 + 0x004) +#define V2D_LAYER_DEC_REG2_L(i) (V2D_L0_DEC_BASE + i * 0x100 + 0x008) +#define V2D_LAYER_DEC_REG3_L(i) (V2D_L0_DEC_BASE + i * 0x100 + 0x00c) +#define V2D_LAYER_DEC_REG4_L(i) (V2D_L0_DEC_BASE + i * 0x100 + 0x010) +#define V2D_LAYER_DEC_REG5_L(i) (V2D_L0_DEC_BASE + i * 0x100 + 0x014) +#define V2D_LAYER_DEC_REG6_L(i) (V2D_L0_DEC_BASE + i * 0x100 + 0x018) +#define V2D_LAYER_DEC_REG7_L(i) (V2D_L0_DEC_BASE + i * 0x100 + 0x01c) +#define V2D_LAYER_DEC_REG8_L(i) (V2D_L0_DEC_BASE + i * 0x100 + 0x020) +#define V2D_LAYER_DEC_REG9_L(i) (V2D_L0_DEC_BASE + i * 0x100 + 0x024) +#define V2D_LAYER_DEC_REG10_L(i) (V2D_L0_DEC_BASE + i * 0x100 + 0x028) +#define V2D_LAYER_DEC_REG11_L(i) (V2D_L0_DEC_BASE + i * 0x100 + 0x02c) +#define V2D_LAYER_DEC_REG12_L(i) (V2D_L0_DEC_BASE + i * 0x100 + 0x030) +#define V2D_LAYER_DEC_REG13_L(i) (V2D_L0_DEC_BASE + i * 0x100 + 0x034) + +#define V2D_ENC_REG0 (V2D_ENC_BASE + 0x000) /* REGISTER HEADER_BASE_ADDR_LOW */ +#define V2D_ENC_REG1 (V2D_ENC_BASE + 0x004) /* REGISTER HEADER_BASE_ADDR_HIGH */ +#define V2D_ENC_REG2 (V2D_ENC_BASE + 0x008) /* REGISTER PAYLOAD_BASE_ADDR_LOW */ +#define V2D_ENC_REG3 (V2D_ENC_BASE + 0x00c) /* REGISTER PAYLOAD_BASE_ADDR_HIGH */ +#define V2D_ENC_REG4 (V2D_ENC_BASE + 0x010) /* REGISTER Bbox_coor_x */ +#define V2D_ENC_REG5 (V2D_ENC_BASE + 0x014) /* REGISTER Bbox_coor_y */ +#define V2D_ENC_REG6 (V2D_ENC_BASE + 0x018) /* REGISTER Y_BUF_BASE_ADDR */ +#define V2D_ENC_REG7 (V2D_ENC_BASE + 0x01c) /* REGISTER Y_BUF_PITCH */ +#define V2D_ENC_REG8 (V2D_ENC_BASE + 0x020) /* REGISTER UV_BUF_BASE_ADDR */ +#define V2D_ENC_REG9 (V2D_ENC_BASE + 0x024) /* REGISTER UV_BUF_PITCH */ +#define V2D_ENC_REG10 (V2D_ENC_BASE + 0x028) /* REGISTER Y_BUF_SIZE */ +#define V2D_ENC_REG11 (V2D_ENC_BASE + 0x02c) /* REGISTER UV_BUF_SIZE */ +#define V2D_ENC_REG12 (V2D_ENC_BASE + 0x030) /* REGISTER REG_SHADOW_CTRL */ +#define V2D_ENC_REG13 (V2D_ENC_BASE + 0x034) /* REGISTER IRQ_MASK */ +#define V2D_ENC_REG14 (V2D_ENC_BASE + 0x038) /* REGISTER IRQ_CLEAR */ +#define V2D_ENC_REG15 (V2D_ENC_BASE + 0x03c) /* REGISTER DMAC_CTRL_0 */ +#define V2D_ENC_REG16 (V2D_ENC_BASE + 0x040) /* REGISTER ENC_MODE */ +#define V2D_ENC_REG17 (V2D_ENC_BASE + 0x044) /* REGISTER DMAC_LENGTH */ +#define V2D_ENC_REG18 (V2D_ENC_BASE + 0x048) /* REGISTER IRQ_STATUS */ +/* v2d iommu */ +#define TBU_NUM 32 +#define V2D_MMU_TTBLR_BASE 0x40 +#define V2D_MMU_TTBHR_BASE 0x44 +#define V2D_MMU_TCR0_BASE 0x48 +#define V2D_MMU_TCR1_BASE 0x4c +#define V2D_MMU_TBU_STATUS_BASE 0x50 +#define V2D_MMU_TBUx_STEP 0x20 +#define V2D_MMU_BVA_LO 0x00 +#define V2D_MMU_BVA_HI 0x04 +#define V2D_MMU_TIMEOUT_VA_ADDR_LO 0x08 +#define V2D_MMU_TIMEOUT_VA_ADDR_HI 0x0C +#define V2D_MMU_IRQ_STATUS 0x10 +#define V2D_MMU_IRQ_ENABLE 0x14 +#define V2D_MMU_TIMEOUT_VALUE 0x18 +#define V2D_MMU_ERROR_CLEAR 0x1C +#define V2D_MMU_LAST_VA_ADDR_LO 0x20 +#define V2D_MMU_LAST_VA_ADDR_HI 0x24 +#define V2D_MMU_LAST_PA_ADDR_LO 0x28 +#define V2D_MMU_LAST_PA_ADDR_HI 0x2C +#define V2D_MMU_VERSION 0x3C +#define V2D_IOMMU_BASE_OFFSET 0xB00 + +/** + *@brief V2D Control register + */ +typedef union +{ + struct + { + unsigned int trigger : 1; /**< trigger v2d to work */ + unsigned int rdma_burst_len : 3; /**< set rdma burst lenght */ + unsigned int reserved1 : 4; /**< Reserved */ + unsigned int wdma_burst_len : 5; /**< set wdma burst length */ + unsigned int reserved2 : 19; /**< Reserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_ctrl_reg_t; + +/** + *@brief V2D DMA Control register + */ +typedef union +{ + struct + { + unsigned int dmac_arb_mode : 2; + unsigned int dmac_arqos : 4; + unsigned int reserved : 2; /**< Reserved */ + unsigned int dmac_awqos : 4; + unsigned int dmac_axi_sec : 1; + unsigned int dmac_max_req_num : 3; + unsigned int dmac_postwr_en : 8; + unsigned int dmac_rst_n_pwr : 1; + unsigned int dmac_rst_req : 1; + unsigned int dmac_user_id : 4; + unsigned int damc_rd_int_clr : 1; + unsigned int damc_wr_int_clr : 1; + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_dma_ctrl_reg_t; + +/** + *@brief V2D Scaler Coefficient register + */ +typedef union +{ + struct + { + int scaler_coef0 : 12; /**< scaler coefficient0 */ + unsigned int reserved1 : 4; /**< Reserved */ + int scaler_coef1 : 12; /**< scaler coefficient1 */ + unsigned int reserved2 : 4; /**< Reserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_scaler_coef_reg_t; + +/** + *@brief V2D Blend Control0 register + */ +typedef union +{ + struct + { + unsigned int bld_mode : 1; /**< blend mode alpha blending or ROP operation */ + unsigned int bld_bg_enable : 1; /**< background color enable */ + unsigned int reserved : 6; /**< Rerserved */ + unsigned int bld_bg_r : 8; /**< background color R value */ + unsigned int bld_bg_g : 8; /**< background color G value */ + unsigned int bld_bg_b : 8; /**< background color B value */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_blend_ctrl0_reg_t; + +/** + *@brief V2D Blend Control1 register + */ +typedef union +{ + struct + { + unsigned int bld_bg_a : 8; /**< background color alpha value */ + unsigned int reserved : 24; /**< Rerserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_blend_ctrl1_reg_t; + +/** + *@brief V2D Blend Mask Control0 register + */ +typedef union +{ + struct + { + unsigned int bld_mask_enable : 2; /**< blend mask enable */ + unsigned int reserved1 : 6; /**< Rerserved */ + unsigned int bld_mask_rect_ltop_x : 16; /**< blend mask rectangle left-top point x-axis coordinate */ + unsigned int reserved2 : 8; /**< Rerserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_blend_mask_ctrl0_reg_t; + +/** + *@brief V2D Blend Mask Control1 register + */ +typedef union +{ + struct + { + unsigned int bld_mask_rect_ltop_y : 16; /**< blend mask rectangle left-top point y-axis coordinate */ + unsigned int bld_mask_rect_width : 16; /**< blend mask rectangle width */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_blend_mask_ctrl1_reg_t; + +/** + *@brief V2D Blend Mask Control2 register + */ +typedef union +{ + struct + { + unsigned int bld_mask_rect_height : 16; /**< blend mask rectangle height */ + unsigned int reserved : 16; /**< Rerserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_blend_mask_ctrl2_reg_t; + +/** + *@brief V2D Output Width register + */ +typedef union +{ + struct + { + unsigned int out_addr_uv_33_32 : 2; /**< output uv address_h_bit */ + unsigned int reserved1 : 6; /**< Rerserved */ + unsigned int out_ori_width : 16; /**< output width */ + unsigned int reserved2 : 8; /**< Rerserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_output_width_reg_t; + +/** + *@brief V2D Output Height register + */ +typedef union +{ + struct + { + unsigned int out_ori_height : 16; /**< output height */ + unsigned int out_ori_stride : 16; /**< output stride */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_output_height_reg_t; + +/** + *@brief V2D Output Control0 register + */ +typedef union +{ + struct + { + unsigned int format : 4; /**< output format */ + unsigned int range : 1; /**< output range yuv narrow/wide */ + unsigned int dither : 2; /**< output dither mode */ + unsigned int swap : 1; /**< output swap */ + unsigned int fbc_en : 1; /**< output fbc enable */ + unsigned int reserved : 7; /**< Rerserved */ + unsigned int crop_ltop_x : 16; /**< output crop left-top point x-axis coordinate */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_output_ctrl0_reg_t; + +/** + *@brief V2D Output Control1 register + */ +typedef union +{ + struct + { + unsigned int crop_ltop_y : 16; /**< output crop left-top point y-axis coordinate */ + unsigned int crop_width : 16; /**< output crop width */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_output_ctrl1_reg_t; + +/** + *@brief V2D Output Control2 register + */ +typedef union +{ + struct + { + unsigned int crop_height : 16; /**< output crop height */ + unsigned int reserved : 16; /**< Rerserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_output_ctrl2_reg_t; + +/** + *@brief V2D mask input Width register + */ +typedef union +{ + struct + { + unsigned int mask_addr_33_32 : 2; /**< mask address_h_bit */ + unsigned int reserved1 : 6; /**< Rerserved */ + unsigned int mask_ori_width : 16; /**< mask in width */ + unsigned int reserved2 : 8; /**< Rerserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_mask_width_reg_t; + +/** + *@brief V2D mask input Height register + */ +typedef union +{ + struct + { + unsigned int mask_ori_height : 16; /**< mask in height */ + unsigned int mask_ori_stride : 16; /**< mask in stride */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_mask_height_reg_t; + +/** + *@brief V2D mask input crop0 register + */ +typedef union +{ + struct + { + unsigned int mask_crop_ltop_x : 16; /**< mask crop left-top point x-axis coordinate */ + unsigned int mask_crop_ltop_y : 16; /**< mask crop left-top point y-axis coordinate */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_mask_crop0_reg_t; + +/** + *@brief V2D mask input crop1 register + */ +typedef union +{ + struct + { + unsigned int mask_crop_width : 16; /**< mask crop in width */ + unsigned int mask_crop_height : 16; /**< mask crop in height */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_mask_crop1_reg_t; + +/** + *@brief V2D Blend Layer Factor register + */ +typedef union +{ + struct + { + unsigned int in_addr_uv_33_32 : 2; /**< input layer uv address_h_bit */ + unsigned int bld_src_color_factor : 3; /**< blend source color factor */ + unsigned int bld_dst_color_factor : 3; /**< blend dst color factor */ + unsigned int bld_src_alpha_factor : 3; /**< blend source alpha factor */ + unsigned int bld_dst_alpha_factor : 3; /**< blend dst alpha factor */ + unsigned int reserved1 : 2; /**< Reserved */ + unsigned int bld_color_rop2_code : 4; /**< ROP color code */ + unsigned int bld_alpha_rop2_code : 4; /**< ROP alpha code */ + unsigned int reserved2 : 8; /**< Reserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_blend_layer_factor_reg_t; + +/** + *@brief V2D Input Layer width/height register + */ +typedef union +{ + struct + { + unsigned int layer_in_ori_width : 16; /**< input layer width */ + unsigned int layer_in_ori_height : 16; /**< input layer height */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_input_layer_width_height_reg_t; + +/** + *@brief V2D Input Layer Control register + */ +typedef union +{ + struct + { + unsigned int stride : 16; /**< input layer stride */ + unsigned int format : 4; /**< input layer format */ + unsigned int rotation : 3; /**< input layer rotation */ + unsigned int swap : 1; /**< input layer swap */ + unsigned int fbc_en : 1; /**< input layer fbc enbale */ + unsigned int reserved : 7; /**< Reserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_input_layer_ctrl_reg_t; + +/** + *@brief V2D input layer crop0 register + */ +typedef union +{ + struct + { + unsigned int layer_in_crop_ltop_x : 16; /**< input layer crop left-top point x-axis coordinate */ + unsigned int layer_in_crop_ltop_y : 16; /**< input layer crop left-top point y-axis coordinate */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_input_layer_crop0_reg_t; + +/** + *@brief V2D input layer crop1 register + */ +typedef union +{ + struct + { + unsigned int layer_in_crop_width : 16; /**< input layer crop in width */ + unsigned int layer_in_crop_height : 16; /**< input layer crop in height */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_input_layer_crop1_reg_t; + +/** + *@brief V2D input solid color control0 register + */ +typedef union +{ + struct + { + unsigned int solid_en : 1; /**< input layer solid color enable */ + unsigned int reserved : 7; /**< Rrserved */ + unsigned int solid_R : 8; /**< solid color R channel value */ + unsigned int solid_G : 8; /**< solid color G channel value */ + unsigned int solid_B : 8; /**< solid color B channel value */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_solid_color_ctrl0_reg_t; + +/** + *@brief V2D input solid color control1 register + */ +typedef union +{ + struct + { + unsigned int solid_A : 8; /**< solid color alpha channel value */ + unsigned int csc_en : 1; /**< input layer csc enable */ + unsigned int reserved1 : 7; /**< Rrserved */ + int csc_matrix0 : 13; /**< input layer csc matrix0 */ + unsigned int reserved2 : 3; /**< Rrserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_solid_color_ctrl1_reg_t; +typedef v2d_solid_color_ctrl1_reg_t v2d_input_layer_csc_ctrl0_reg_t; + +/** + *@brief V2D input layer csc control1~5 register + */ +typedef union +{ + struct + { + int csc_matrix1 : 13; /**< input layer csc matrix 2*i-1 */ + unsigned int reserved1 : 3; /**< Rrserved */ + int csc_matrix2 : 13; /**< input layer csc matrix 2*i */ + unsigned int reserved2 : 3; /**< Rrserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_input_layer_csc_ctrl1_reg_t; + +/** + *@brief V2D input layer csc control6 register + */ +typedef union +{ + struct + { + int csc_matrix11 : 13; /**< input layer csc matrix11 */ + unsigned int scl_mode : 2; /**< scaler mode 0:bypass, 1:scale down, 2:scale up */ + unsigned int reserved1 : 17; /**< Rrserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_input_layer_csc_ctrl2_reg_t; +typedef v2d_input_layer_csc_ctrl2_reg_t v2d_input_layer_scale_mode_reg_t; + +/** + *@brief V2D input layer scale delta x register + */ +typedef union +{ + struct + { + unsigned int scl_delta_x : 20; /**< input layer scale delta x, (in_width<<16) /bld_rectWidth */ + unsigned int reserved : 12; /**< Rrserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_input_layer_scale_delta_x_reg_t; + +/** + *@brief V2D input layer scale delta y register + */ +typedef union +{ + struct + { + unsigned int scl_delta_y : 20; /**< input layer scale delta y, (in_height<<16) /bld_rectHeight */ + unsigned int bld_alpha_source : 2; /**< blend alpha source, 0:pixel, 1:golbal, 2: mask value */ + unsigned int bld_pre_alp_func : 2; /**< blend premultiplied function, 0:disable, 1:global alpha* src_alpha, 2:mask*src_a */ + unsigned int bld_glb_alp : 8; /**< global alpha value */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_input_layer_scale_delta_y_reg_t; +typedef v2d_input_layer_scale_delta_y_reg_t v2d_blend_layer_ctrl0_reg_t; + +/** + * @brief V2D Blend Layer Control1 register + */ +typedef union +{ + struct + { + unsigned int blend_en : 1; /**< blend layer enable */ + unsigned int reserved1 : 7; /**< Reserved */ + unsigned int bld_rect_ltop_x : 16; /**< blend layer rectangle left-top point x-axis coordinate */ + unsigned int reserved2 : 8; /**< Reserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_blend_layer_ctrl1_reg_t; + +/** + * @brief V2D Blend Layer Control2 register + */ +typedef union +{ + struct + { + unsigned int bld_rect_ltop_y : 16; /**< blend layer rectangle left-top point y-axis coordinate */ + unsigned int bld_rect_width : 16; /**< blend layer rectangle width */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_blend_layer_ctrl2_reg_t; + +/** + * @brief V2D Blend Layer Control3 register + */ +typedef union +{ + struct + { + unsigned int bld_rect_height : 16; /**< blend layer rectangle height */ + unsigned int reserved : 16; /**< Reserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_blend_layer_ctrl3_reg_t; + +/** + * @brief V2D FBC decoder bbox register + */ +typedef union +{ + struct + { + unsigned int bbox_start : 13; /**< v2d fbc decoder bbox start */ + unsigned int reserved1 : 3; /**< Reserved */ + unsigned int bbox_end : 13; /**< v2d fbc decoder bbox end */ + unsigned int reserved2 : 3; /**< Reserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_fbc_decoder_bbox_reg_t; + +/** + * @brief V2D FBC decoder image size register + */ +typedef union +{ + struct + { + unsigned int width : 16; /**< v2d fbc decoder image width */ + unsigned int height : 16; /**< v2d fbc decoder image height */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_fbc_decoder_imgae_size_reg_t; + +/** + * @brief V2D FBC decoder mode register + */ +typedef union +{ + struct + { + unsigned int mode : 3; /**< v2d fbc decoder mode */ + unsigned int format : 3; /**< v2d fbc decoder pixel format */ + unsigned int is_split : 1; /**< v2d fbc decoder split mode */ + unsigned int rgb_pack_en : 1; /**< v2d fbc decoder rgb pack enable */ + unsigned int reserved : 24; /**< Reserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_fbc_decoder_mode_reg_t; + +/** + * @brief V2D FBC decoder dma control register + */ +typedef union +{ + struct + { + unsigned int dmac_arqos : 4; /**< v2d fbc decoder dma qos */ + unsigned int damc_axi_sec : 1; /**< v2d fbc decoder dma axi sec */ + unsigned int dmac_user_id : 4; /**< v2d fbc decoder dma user id */ + unsigned int dmac_rstn_pwr : 1; /**< v2d fbc decoder dma rstn pwr */ + unsigned int dmac_rst_req : 1; /**< v2d fbc decoder dma rst req*/ + unsigned int dmac_max_req_num : 3; /**< v2d fbc decoder dma max req num */ + unsigned int dmac_arb_mode : 2; /**< v2d fbc decoder dma arb mode */ + unsigned int rdma_timeout_num : 16; /**< v2d fbc decoder dma timeout num */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_fbc_decoder_dma_ctrl_reg_t; + +/** + * @brief V2D FBC decoder irq mask/raw/status register + */ +typedef union +{ + struct + { + unsigned int decode_eof : 1; /**< v2d fbc decoder eof irq mask */ + unsigned int cfg_swaped : 1; /**< v2d fbc decoder cfg sswap irq mask */ + unsigned int dmac_err : 1; /**< v2d fbc decoder dmac err irq mask */ + unsigned int rdma_timeout : 1; /**< v2d fbc decoder rdma timeout mask */ + unsigned int dec_err : 1; /**< v2d fbc decoder decode err irq mask */ + unsigned int reserved : 27; /**< Reserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_fbc_decoder_irq_ctrl_reg_t; + +/** + * @brief V2D FBC decoder trigger register + */ +typedef union +{ + struct + { + unsigned int direct_swap : 1; /**< v2d fbc decoder direct swap */ + unsigned int pending_swap : 1; /**< v2d fbc decoder pending swap */ + unsigned int reserved : 30; /**< Reserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_fbc_decoder_trigger_reg_t; + +/** + * @brief V2D FBC encoder bbox register + */ +typedef union +{ + struct + { + unsigned int bbox_start : 16; /**< v2d fbc encoder bbox start */ + unsigned int bbox_end : 16; /**< v2d fbc encoder bbox end */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_fbc_encoder_bbox_reg_t; + +/** + * @brief V2D FBC encoder y or uv buf szie register + */ +typedef union +{ + struct + { + unsigned int x_size : 16; /**< v2d fbc encoder buf x size */ + unsigned int y_size : 16; /**< v2d fbc encoder buf y size */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_fbc_encoder_buf_size_reg_t; + +/** + * @brief V2D FBC encoder trigger register + */ +typedef union +{ + struct + { + unsigned int direct_swap : 1; /**< v2d fbc encoder direct swap */ + unsigned int pending_swap : 1; /**< v2d fbc encoder pending swap */ + unsigned int reserved : 30; /**< Reserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_fbc_encoder_trigger_reg_t; + +/** + * @brief V2D FBC encoder irq mask,raw,status register + */ +typedef union +{ + struct + { + unsigned int dma_wr_err : 16; /**< v2d fbc encoder dma wr err */ + unsigned int dma_wr_eof : 1; /**< v2d fbc encoder dma wr eof */ + unsigned int cfg_update_done : 1; /**< v2d fbc encoder cfg update done */ + unsigned int reserved : 14; /**< Reserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_fbc_encoder_irq_reg_t; + +/** + * @brief V2D FBC encoder mode register + */ +typedef union +{ + struct + { + unsigned int encode_enable : 1; /**< v2d fbc encoder enable */ + unsigned int split_mode_en : 1; /**< v2d fbc encoder split mode */ + unsigned int img_pix_format : 2; /**< v2d fbc encoder pixel format */ + unsigned int reserved : 28; /**< Reserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_fbc_encoder_mode_reg_t; + +/** + * @brief V2D FBC encoder dmac length register + */ +typedef union +{ + struct + { + unsigned int burst_length : 7; /**< v2d fbc encoder dmac burst length */ + unsigned int reserved : 25; /**< Reserved */ + } field; /**< Fields view */ + unsigned int overlay; /**< Overlay view */ +} v2d_fbc_encoder_dmac_burst_reg_t; + +/** +*@brief V2D Top AXI bus control register +*/ +typedef union +{ + struct + { + unsigned int arqos_m : 4; /**< v2d axi bus read qos */ + unsigned int aruser_m : 4; /**< v2d axi bus read user */ + unsigned int awqos_m : 4; /** + +#include +#include +#include +#include + +#define QSPI_WAIT_TIMEOUT 300 /* ms */ +#define QSPI_AUTOSUSPEND_TIMEOUT 2000 +#define K1X_MPMU_ACGR 0xd4051024 + +/* QSPI PMUap register */ +#define PMUA_QSPI_CLK_RES_CTRL 0xd4282860 +#define QSPI_CLK_SEL(x) ((x) << 6) +#define QSPI_CLK_SEL_MASK RT_GENMASK(8, 6) +#define QSPI_CLK_EN RT_BIT(4) +#define QSPI_BUS_CLK_EN RT_BIT(3) +#define QSPI_CLK_RST RT_BIT(1) +#define QSPI_BUS_RST RT_BIT(0) + +/* QSPI memory base */ +#define QSPI_AMBA_BASE(qspi) ((qspi)->memmap_base) +#define QSPI_FLASH_A1_BASE(qspi) QSPI_AMBA_BASE(qspi) +#define QSPI_FLASH_A1_TOP(qspi) (QSPI_FLASH_A1_BASE(qspi) + 0x4000000) +#define QSPI_FLASH_A2_BASE(qspi) QSPI_FLASH_A1_TOP(qspi) +#define QSPI_FLASH_A2_TOP(qspi) (QSPI_FLASH_A2_BASE(qspi) + 0x100000) +#define QSPI_FLASH_B1_BASE(qspi) QSPI_FLASH_A2_TOP(qspi) +#define QSPI_FLASH_B1_TOP(qspi) (QSPI_FLASH_B1_BASE(qspi) + 0x100000) +#define QSPI_FLASH_B2_BASE(qspi) QSPI_FLASH_B1_TOP(qspi) +#define QSPI_FLASH_B2_TOP(qspi) (QSPI_FLASH_B2_BASE(qspi) + 0x100000) + +/* TX/RX/ABH buffer max */ +#define QSPI_RX_BUFF_MAX 128 +#define QSPI_TX_BUFF_MAX 256 +#define QSPI_TX_BUFF_POP_MIN 16 +#define QSPI_AHB_BUFF_MAX_SIZE 512 +#define QSPI_TX_DMA_BURST 16 + +#define QSPI_WAIT_BIT_CLEAR 0 +#define QSPI_WAIT_BIT_SET 1 + +/* QSPI Host Registers used by the driver */ +#define QSPI_MCR 0x00 +#define QSPI_MCR_ISD_MASK RT_GENMASK(19, 16) +#define QSPI_MCR_MDIS_MASK RT_BIT(14) +#define QSPI_MCR_CLR_TXF_MASK RT_BIT(11) +#define QSPI_MCR_CLR_RXF_MASK RT_BIT(10) +#define QSPI_MCR_DDR_EN_MASK RT_BIT(7) +#define QSPI_MCR_END_CFG_MASK RT_GENMASK(3, 2) +#define QSPI_MCR_SWRSTHD_MASK RT_BIT(1) +#define QSPI_MCR_SWRSTSD_MASK RT_BIT(0) + +#define QSPI_TCR 0x04 +#define QSPI_IPCR 0x08 +#define QSPI_IPCR_SEQID(x) ((x) << 24) + +#define QSPI_FLSHCR 0x0c + +#define QSPI_BUF0CR 0x10 +#define QSPI_BUF1CR 0x14 +#define QSPI_BUF2CR 0x18 +#define QSPI_BUF3CR 0x1c +#define QSPI_BUF3CR_ALLMST_MASK RT_BIT(31) +#define QSPI_BUF3CR_ADATSZ(x) ((x) << 8) +#define QSPI_BUF3CR_ADATSZ_MASK RT_GENMASK(15, 8) + +#define QSPI_BFGENCR 0x20 +#define QSPI_BFGENCR_SEQID(x) ((x) << 12) + +#define QSPI_SOCCR 0x24 + +#define QSPI_BUF0IND 0x30 +#define QSPI_BUF1IND 0x34 +#define QSPI_BUF2IND 0x38 + +#define QSPI_SFAR 0x100 +#define QSPI_SFACR 0x104 + +#define QSPI_SMPR 0x108 +#define QSPI_SMPR_DDRSMP_MASK RT_GENMASK(18, 16) +#define QSPI_SMPR_FSDLY_MASK RT_BIT(6) +#define QSPI_SMPR_FSPHS_MASK RT_BIT(5) +#define QSPI_SMPR_FSPHS_CLK (416000000) +#define QSPI_SMPR_HSENA_MASK RT_BIT(0) + +#define QSPI_RBSR 0x10c + +#define QSPI_RBCT 0x110 +#define QSPI_RBCT_WMRK_MASK RT_GENMASK(4, 0) +#define QSPI_RBCT_RXBRD_MASK RT_BIT(8) + +#define QSPI_TBSR 0x150 +#define QSPI_TBDR 0x154 +#define QSPI_TBCT 0x158 +#define QSPI_TX_WMRK (QSPI_TX_DMA_BURST / 4 - 1) + +#define QSPI_SR 0x15c +#define QSPI_SR_BUSY RT_BIT(0) +#define QSPI_SR_IP_ACC_MASK RT_BIT(1) +#define QSPI_SR_AHB_ACC_MASK RT_BIT(2) +#define QSPI_SR_TXFULL RT_BIT(27) + +#define QSPI_FR 0x160 +#define QSPI_FR_TFF_MASK RT_BIT(0) +#define QSPI_FR_IPGEF RT_BIT(4) +#define QSPI_FR_IPIEF RT_BIT(6) +#define QSPI_FR_IPAEF RT_BIT(7) +#define QSPI_FR_IUEF RT_BIT(11) +#define QSPI_FR_ABOF RT_BIT(12) +#define QSPI_FR_AIBSEF RT_BIT(13) +#define QSPI_FR_AITEF RT_BIT(14) +#define QSPI_FR_ABSEF RT_BIT(15) +#define QSPI_FR_RBDF RT_BIT(16) +#define QSPI_FR_RBOF RT_BIT(17) +#define QSPI_FR_ILLINE RT_BIT(23) +#define QSPI_FR_TBUF RT_BIT(26) +#define QSPI_FR_TBFF RT_BIT(27) +#define BUFFER_FR_FLAG (QSPI_FR_ABOF| QSPI_FR_RBOF| QSPI_FR_TBUF) + +#define COMMAND_FR_FLAG (QSPI_FR_ABSEF | QSPI_FR_AITEF | QSPI_FR_AIBSEF | QSPI_FR_IUEF | \ + QSPI_FR_IPAEF |QSPI_FR_IPIEF | QSPI_FR_IPGEF) + +#define QSPI_RSER 0x164 +#define QSPI_RSER_TFIE RT_BIT(0) +#define QSPI_RSER_IPGEIE RT_BIT(4) +#define QSPI_RSER_IPIEIE RT_BIT(6) +#define QSPI_RSER_IPAEIE RT_BIT(7) +#define QSPI_RSER_IUEIE RT_BIT(11) +#define QSPI_RSER_ABOIE RT_BIT(12) +#define QSPI_RSER_AIBSIE RT_BIT(13) +#define QSPI_RSER_AITIE RT_BIT(14) +#define QSPI_RSER_ABSEIE RT_BIT(15) +#define QSPI_RSER_RBDIE RT_BIT(16) +#define QSPI_RSER_RBOIE RT_BIT(17) +#define QSPI_RSER_RBDDE RT_BIT(21) +#define QSPI_RSER_ILLINIE RT_BIT(23) +#define QSPI_RSER_TBFDE RT_BIT(25) +#define QSPI_RSER_TBUIE RT_BIT(26) +#define QSPI_RSER_TBFIE RT_BIT(27) +#define BUFFER_ERROR_INT (QSPI_RSER_ABOIE| QSPI_RSER_RBOIE | QSPI_RSER_TBUIE) + +#define COMMAND_ERROR_INT (QSPI_RSER_ABSEIE | QSPI_RSER_AITIE | QSPI_RSER_AIBSIE | QSPI_RSER_IUEIE | \ + QSPI_RSER_IPAEIE |QSPI_RSER_IPIEIE | QSPI_RSER_IPGEIE) + +#define QSPI_SPNDST 0x168 +#define QSPI_SPTRCLR 0x16c +#define QSPI_SPTRCLR_IPPTRC RT_BIT(8) +#define QSPI_SPTRCLR_BFPTRC RT_BIT(0) + +#define QSPI_SFA1AD 0x180 +#define QSPI_SFA2AD 0x184 +#define QSPI_SFB1AD 0x188 +#define QSPI_SFB2AD 0x18c +#define QSPI_DLPR 0x190 +#define QSPI_RBDR(x) (0x200 + ((x) * 4)) + +#define QSPI_LUTKEY 0x300 +#define QSPI_LUTKEY_VALUE 0x5af05af0 + +#define QSPI_LCKCR 0x304 +#define QSPI_LCKER_LOCK RT_BIT(0) +#define QSPI_LCKER_UNLOCK RT_BIT(1) + +#define QSPI_LUT_BASE 0x310 +/* 16Bytes per sequence */ +#define QSPI_LUT_REG(seqid, i) (QSPI_LUT_BASE + (seqid) * 16 + (i) * 4) + +/* + * QSPI Sequence index. + * index 0 is preset at boot for AHB read, + * index 1 is used for other command. + */ +#define SEQID_LUT_AHBREAD_ID 0 +#define SEQID_LUT_SHARED_ID 1 + +/* QSPI Instruction set for the LUT register */ +#define LUT_INSTR_STOP 0 +#define LUT_INSTR_CMD 1 +#define LUT_INSTR_ADDR 2 +#define LUT_INSTR_DUMMY 3 +#define LUT_INSTR_MODE 4 +#define LUT_INSTR_MODE2 5 +#define LUT_INSTR_MODE4 6 +#define LUT_INSTR_READ 7 +#define LUT_INSTR_WRITE 8 +#define LUT_INSTR_JMP_ON_CS 9 +#define LUT_INSTR_ADDR_DDR 10 +#define LUT_INSTR_MODE_DDR 11 +#define LUT_INSTR_MODE2_DDR 12 +#define LUT_INSTR_MODE4_DDR 13 +#define LUT_INSTR_READ_DDR 14 +#define LUT_INSTR_WRITE_DDR 15 +#define LUT_INSTR_DATA_LEARN 16 + +/* + * The PAD definitions for LUT register. + * + * The pad stands for the number of IO lines [0:3]. + * For example, the quad read needs four IO lines, + * so you should use LUT_PAD(4). + */ +#define LUT_PAD(x) (fls(x) - 1) + +/* + * One sequence must be consisted of 4 LUT enteries(16Bytes). + * LUT entries with the following register layout: + * b'31 b'0 + * --------------------------------------------------------------------------- + * |INSTR1[15~10]|PAD1[9~8]|OPRND1[7~0] | INSTR0[15~10]|PAD0[9~8]|OPRND0[7~0]| + * --------------------------------------------------------------------------- + */ +#define LUT_DEF(idx, ins, pad, opr) ((((ins) << 10) | ((pad) << 8) | (opr)) << (((idx) & 0x1) * 16)) + +#define READ_FROM_CACHE_OP 0x03 +#define READ_FROM_CACHE_OP_Fast 0x0b +#define READ_FROM_CACHE_OP_X2 0x3b +#define READ_FROM_CACHE_OP_X4 0x6b +#define READ_FROM_CACHE_OP_DUALIO 0xbb +#define READ_FROM_CACHE_OP_QUADIO 0xeb + +enum qpsi_cs +{ + QSPI_CS_A1 = 0, + QSPI_CS_A2, + QSPI_CS_B1, + QSPI_CS_B2, + QSPI_CS_MAX, + QSPI_DEFAULT_CS = QSPI_CS_A1, +}; + +enum qpsi_mode +{ + QSPI_NORMAL_MODE = 0, + QSPI_DISABLE_MODE, + QSPI_STOP_MODE, +}; + +struct k1x_qspi +{ + struct rt_spi_bus parent; + + struct rt_clk *clk; + struct rt_clk *bus_clk; + struct rt_reset_control *rstc; + + int irq; + void *io_map; + rt_ubase_t io_phys; + + void *ahb_map; + rt_ubase_t memmap_base; + rt_ubase_t memmap_size; + + rt_uint32_t sfa1ad; + rt_uint32_t sfa2ad; + rt_uint32_t sfb1ad; + rt_uint32_t sfb2ad; + + void *pmuap_addr; + void *mpmu_acgr; + rt_uint32_t pmuap_reg; + rt_uint32_t mpmu_acgr_reg; + + rt_uint32_t rx_buf_size; + rt_uint32_t tx_buf_size; + rt_uint32_t ahb_buf_size; + rt_uint32_t ahb_read_enable; + rt_uint32_t tx_unit_size; + rt_uint32_t rx_unit_size; + + rt_uint32_t cmd_interrupt; + rt_uint32_t fr_error_flag; + + rt_uint32_t cs_selected; + rt_uint32_t max_hz; + rt_uint32_t endian_xchg; + rt_uint32_t dma_enable; + + rt_uint32_t tx_wmrk; + rt_uint32_t tx_dma_enable; + rt_uint32_t rx_dma_enable; + + struct rt_dma_slave_config rx_config; + struct rt_dma_slave_config tx_config; + struct rt_dma_slave_transfer rx_transfer; + struct rt_dma_slave_transfer tx_transfer; + + struct rt_dma_chan *dma_rx; + struct rt_dma_chan *dma_tx; + + struct rt_completion cmd_completion; + struct rt_completion dma_completion; +}; + +#define raw_to_k1x_qspi(raw) rt_container_of(raw, struct k1x_qspi, parent) + +static void qspi_writel(struct k1x_qspi *qspi, rt_uint32_t val, void *addr) +{ + if (qspi->endian_xchg) + { + HWREG32(addr) = rt_cpu_to_be32(val); + } + else + { + HWREG32(addr) = val; + } +} + +static rt_uint32_t qspi_readl(struct k1x_qspi *qspi, void *addr) +{ + if (qspi->endian_xchg) + { + return rt_be32_to_cpu(HWREG32(addr)); + } + else + { + return HWREG32(addr); + } +} + +static rt_err_t k1x_qspi_readl_poll_tout(struct k1x_qspi *qspi, void *base, + rt_uint32_t mask, rt_uint32_t timeout_us, rt_uint8_t wait_set) +{ + rt_uint32_t reg; + + if (qspi->endian_xchg) + { + mask = __builtin_bswap32(mask); + } + + if (wait_set) + { + return readl_poll_timeout(base, reg, (reg & mask), 10, timeout_us); + } + else + { + return readl_poll_timeout(base, reg, !(reg & mask), 10, timeout_us); + } +} + +static void qspi_reset(struct k1x_qspi *qspi) +{ + rt_uint32_t reg; + + /* QSPI_SR[QSPI_SR_BUSY] must be 0 */ + if (k1x_qspi_readl_poll_tout(qspi, qspi->io_map + QSPI_SR, + QSPI_SR_BUSY, QSPI_WAIT_TIMEOUT*1000, QSPI_WAIT_BIT_CLEAR)) + { + return; + } + + /* qspi softreset first */ + reg = qspi_readl(qspi, qspi->io_map + QSPI_MCR); + reg |= QSPI_MCR_SWRSTHD_MASK | QSPI_MCR_SWRSTSD_MASK; + qspi_writel(qspi, reg, qspi->io_map + QSPI_MCR); + reg = qspi_readl(qspi, qspi->io_map + QSPI_MCR); + + if ((reg & 0x3) != 0x3) + { + LOG_I("Reset ignored %#x", reg); + } + + rt_hw_us_delay(1); + reg &= ~(QSPI_MCR_SWRSTHD_MASK | QSPI_MCR_SWRSTSD_MASK); + qspi_writel(qspi, reg, qspi->io_map + QSPI_MCR); +} + +static void qspi_enter_mode(struct k1x_qspi *qspi, rt_uint32_t mode) +{ + rt_uint32_t mcr; + + mcr = qspi_readl(qspi, qspi->io_map + QSPI_MCR); + if (mode == QSPI_NORMAL_MODE) + { + mcr &= ~QSPI_MCR_MDIS_MASK; + } + else if (mode == QSPI_DISABLE_MODE) + { + mcr |= QSPI_MCR_MDIS_MASK; + } + qspi_writel(qspi, mcr, qspi->io_map + QSPI_MCR); +} + +static void qspi_write_sfar(struct k1x_qspi *qspi, rt_uint32_t val) +{ + /* QSPI_SR[IP_ACC] must be 0 */ + if (k1x_qspi_readl_poll_tout(qspi, qspi->io_map + QSPI_SR, + QSPI_SR_IP_ACC_MASK, QSPI_WAIT_TIMEOUT*1000, QSPI_WAIT_BIT_CLEAR)) + { + return; + } + qspi_writel(qspi, val, qspi->io_map + QSPI_SFAR); +} + +/* + * IP Command Trigger could not be executed Error Flag may happen for write + * access to RBCT/SFAR register, need retry for these two register + */ +static void qspi_write_rbct(struct k1x_qspi *qspi, rt_uint32_t val) +{ + /* QSPI_SR[IP_ACC] must be 0 */ + if (k1x_qspi_readl_poll_tout(qspi, qspi->io_map + QSPI_SR, + QSPI_SR_IP_ACC_MASK, QSPI_WAIT_TIMEOUT*1000, QSPI_WAIT_BIT_CLEAR)) + { + return; + } + + qspi_writel(qspi, val, qspi->io_map + QSPI_RBCT); +} + +/* + * If the slave device content being changed by Write/Erase, need to + * invalidate the AHB buffer. This can be achieved by doing the reset + * of controller after setting MCR0[SWRESET] bit. + */ +rt_inline void k1x_qspi_invalid(struct k1x_qspi *qspi) +{ + rt_uint32_t reg; + + reg = qspi_readl(qspi, qspi->io_map + QSPI_MCR); + reg |= QSPI_MCR_SWRSTHD_MASK | QSPI_MCR_SWRSTSD_MASK; + qspi_writel(qspi, reg, qspi->io_map + QSPI_MCR); + + /* + * The minimum delay : 1 AHB + 2 SFCK clocks. + * Delay 1 us is enough. + */ + rt_hw_us_delay(1); + + reg &= ~(QSPI_MCR_SWRSTHD_MASK | QSPI_MCR_SWRSTSD_MASK); + qspi_writel(qspi, reg, qspi->io_map + QSPI_MCR); +} + +static void k1x_qspi_prepare_lut(struct k1x_qspi *qspi, + struct rt_qspi_message *qxfer, rt_uint32_t seq_id) +{ + int lutidx = 0; + rt_uint32_t lutval[4] = {}; + + /* qspi cmd */ + lutval[0] |= LUT_DEF(lutidx, LUT_INSTR_CMD, + LUT_PAD(qxfer->instruction.qspi_lines), qxfer->instruction.content); + lutidx++; + + /* addr bytes */ + if (qxfer->address.size) + { + lutval[lutidx / 2] |= LUT_DEF(lutidx, LUT_INSTR_ADDR, + LUT_PAD(qxfer->address.qspi_lines), qxfer->address.size * 8); + lutidx++; + } + + /* dummy bytes, if needed */ + if (qxfer->alternate_bytes.size) + { + lutval[lutidx / 2] |= LUT_DEF(lutidx, LUT_INSTR_DUMMY, + LUT_PAD(qxfer->alternate_bytes.qspi_lines), + qxfer->alternate_bytes.size * 8 / qxfer->alternate_bytes.qspi_lines); + lutidx++; + } + + /* read/write data bytes */ + if (qxfer->parent.length) + { + lutval[lutidx / 2] |= LUT_DEF(lutidx, + qxfer->parent.recv_buf ? LUT_INSTR_READ : LUT_INSTR_WRITE, + LUT_PAD(qxfer->qspi_data_lines), 0); + lutidx++; + } + + /* stop condition. */ + lutval[lutidx / 2] |= LUT_DEF(lutidx, LUT_INSTR_STOP, 0, 0); + + /* unlock LUT */ + qspi_writel(qspi, QSPI_LUTKEY_VALUE, qspi->io_map + QSPI_LUTKEY); + qspi_writel(qspi, QSPI_LCKER_UNLOCK, qspi->io_map + QSPI_LCKCR); + + /* fill LUT register */ + for (int i = 0; i < RT_ARRAY_SIZE(lutval); ++i) + { + qspi_writel(qspi, lutval[i], qspi->io_map + QSPI_LUT_REG(seq_id, i)); + } + + /* lock LUT */ + qspi_writel(qspi, QSPI_LUTKEY_VALUE, qspi->io_map + QSPI_LUTKEY); + qspi_writel(qspi, QSPI_LCKER_LOCK, qspi->io_map + QSPI_LCKCR); +} + +static void k1x_qspi_enable_interrupt(struct k1x_qspi *qspi, rt_uint32_t val) +{ + rt_uint32_t resr = 0; + + resr = qspi_readl(qspi, qspi->io_map + QSPI_RSER); + resr |= val; + qspi_writel(qspi, resr, qspi->io_map + QSPI_RSER); +} + +static void k1x_qspi_disable_interrupt(struct k1x_qspi *qspi, rt_uint32_t val) +{ + rt_uint32_t resr = 0; + + resr = qspi_readl(qspi, qspi->io_map + QSPI_RSER); + resr &= ~val; + qspi_writel(qspi, resr, qspi->io_map + QSPI_RSER); +} + +static void k1x_qspi_dma_callback(struct rt_dma_chan *chan, rt_size_t size) +{ + struct k1x_qspi *qspi = chan->priv; + + rt_completion_done(&qspi->dma_completion); +} + +static rt_err_t k1x_qspi_tx_dma_exec(struct k1x_qspi *qspi, struct rt_qspi_message *qxfer) +{ + rt_err_t err; + + qspi->tx_config.src_addr = (rt_ubase_t)rt_kmem_v2p((void *)qxfer->parent.send_buf); + + if ((err = rt_dma_chan_config(qspi->dma_tx, &qspi->tx_config))) + { + return err; + } + + qspi->tx_transfer.buffer_len = qxfer->parent.length; + qspi->tx_transfer.src_addr = qspi->tx_config.src_addr; + + if ((err = rt_dma_prep_single(qspi->dma_tx, &qspi->tx_transfer))) + { + return err; + } + + if ((err = rt_dma_chan_start(qspi->dma_tx))) + { + return err; + } + + return rt_completion_wait(&qspi->dma_completion, RT_WAITING_FOREVER); +} + +static rt_err_t k1x_qspi_rx_dma_exec(struct k1x_qspi *qspi, struct rt_qspi_message *qxfer) +{ + rt_err_t err; + + qspi->rx_config.dst_addr = (rt_ubase_t)rt_kmem_v2p(qxfer->parent.recv_buf); + + if ((err = rt_dma_chan_config(qspi->dma_rx, &qspi->rx_config))) + { + return err; + } + + qspi->rx_transfer.buffer_len = qxfer->parent.length; + qspi->rx_transfer.dst_addr = qspi->rx_config.dst_addr; + + if ((err = rt_dma_prep_memcpy(qspi->dma_rx, &qspi->rx_transfer))) + { + return err; + } + + if ((err = rt_dma_chan_start(qspi->dma_rx))) + { + return err; + } + + return rt_completion_wait(&qspi->dma_completion, + rt_tick_from_millisecond(qxfer->parent.length)); +} + +static rt_err_t k1x_qspi_ahb_read(struct k1x_qspi *qspi, struct rt_qspi_message *qxfer) +{ + rt_err_t err; + rt_uint32_t len = qxfer->parent.length, from = qxfer->address.content; + + /* Read out the data directly from the AHB buffer. */ + if (from + len > qspi->memmap_size) + { + return -RT_ENOSYS; + } + + /* Firstly try the DMA */ + if (qspi->rx_dma_enable) + { + if (!(err = k1x_qspi_rx_dma_exec(qspi, qxfer))) + { + return RT_EOK; + } + else + { + LOG_D("Read rx dma fallback to memcpy read"); + } + } + + rt_memcpy(qxfer->parent.recv_buf, (qspi->ahb_map + qxfer->address.content), len); + + return RT_EOK; +} + +static rt_err_t k1x_qspi_fill_txfifo(struct k1x_qspi *qspi, struct rt_qspi_message *qxfer) +{ + int i; + void *base = qspi->io_map; + rt_uint32_t val, tbsr, wait_cnt; + rt_size_t length = qxfer->parent.length; + + if (!qspi->tx_dma_enable || (length % QSPI_TX_BUFF_POP_MIN)) + { + qspi->tx_wmrk = 0; + for (i = 0; i < RT_ALIGN_DOWN(length, 4); i += 4) + { + rt_memcpy(&val, qxfer->parent.send_buf + i, 4); + qspi_writel(qspi, val, base + QSPI_TBDR); + } + + if (i < length) + { + rt_memcpy(&val, qxfer->parent.send_buf + i, length - i); + qspi_writel(qspi, val, base + QSPI_TBDR); + } + + /* + * There must be at least 128bit data available in TX FIFO + * for any pop operation otherwise QSPI_FR[TBUF] will be set + */ + for (i = length; i < RT_ALIGN_DOWN(length + (QSPI_TX_BUFF_POP_MIN - 1), QSPI_TX_BUFF_POP_MIN); i += 4) + { + qspi_writel(qspi, 0, base + QSPI_TBDR); + } + } + else + { + /* + * Note that the number of bytes per DMA loop is determined + * by thee size of the QSPI_TBCT[WMRK]. + * bytes per DMA loop = (QSPI_TBCT[WMRK] + 1) * 4. + * set QSPI_TX_WMRK as the TX watermark. + */ + qspi->tx_wmrk = QSPI_TX_WMRK; + qspi_writel(qspi, qspi->tx_wmrk, base + QSPI_TBCT); + + /* Config DMA channel and start */ + if (k1x_qspi_tx_dma_exec(qspi, qxfer)) + { + qspi->tx_wmrk = 0; + LOG_E("Failed to start tx dma"); + return -RT_EIO; + } + + /* Enable DMA request */ + k1x_qspi_enable_interrupt(qspi, QSPI_RSER_TBFDE); + + /* + * before trigger qspi to send data to external bus, TX bufer + * need to have some data, or underrun error may happen. + * DMA need some time to write data to TX buffer, so add + * a delay here for this requirement. + */ + wait_cnt = 0; + tbsr = qspi_readl(qspi, base + QSPI_TBSR); + + while (4 * (tbsr >> 16) < rt_min_t(unsigned int, qspi->tx_buf_size, length)) + { + rt_hw_us_delay(1); + tbsr = qspi_readl(qspi, base + QSPI_TBSR); + + if (wait_cnt++ >= 100) + { + rt_thread_mdelay(100); + tbsr = qspi_readl(qspi, base + QSPI_TBSR); + + if (4 * (tbsr >> 16) < rt_min_t(unsigned int, qspi->tx_buf_size, length)) + { + LOG_E("Failed to fill tx dma"); + /* Disable all interrupts */ + qspi_writel(qspi, 0, qspi->io_map + QSPI_RSER); + rt_dma_chan_stop(qspi->dma_tx); + qspi->tx_wmrk = 0; + + return -RT_EIO; + } + else + { + break; + } + } + } + } + + return RT_EOK; +} + +static void k1x_qspi_read_rxfifo(struct k1x_qspi *qspi, struct rt_qspi_message *qxfer) +{ + int i; + rt_uint32_t val; + rt_uint8_t *buf; + void *base = qspi->io_map; + rt_size_t length = qxfer->parent.length; + + buf = qxfer->parent.recv_buf; + + for (i = 0; i < RT_ALIGN_DOWN(length, 4); i += 4) + { + val = qspi_readl(qspi, base + QSPI_RBDR(i / 4)); + rt_memcpy(buf + i, &val, 4); + } + + if (i < length) + { + val = qspi_readl(qspi, base + QSPI_RBDR(i / 4)); + rt_memcpy(buf + i, &val, length - i); + } +} + +static rt_err_t k1x_qspi_do_op(struct k1x_qspi *qspi, struct rt_qspi_message *qxfer) +{ + rt_uint32_t mcr; + rt_err_t err = RT_EOK; + void *base = qspi->io_map; + rt_size_t length = qxfer->parent.length; + + if (qspi->cmd_interrupt) + { + k1x_qspi_enable_interrupt(qspi, QSPI_RSER_TFIE | BUFFER_ERROR_INT | COMMAND_ERROR_INT); + } + + /* Trigger LUT */ + qspi_writel(qspi, length | QSPI_IPCR_SEQID(SEQID_LUT_SHARED_ID), base + QSPI_IPCR); + + /* Wait for the transaction complete */ + if (qspi->cmd_interrupt) + { + rt_completion_wait(&qspi->cmd_completion, RT_WAITING_FOREVER); + } + else + { + err = k1x_qspi_readl_poll_tout(qspi, base + QSPI_FR, QSPI_FR_TFF_MASK, + QSPI_WAIT_TIMEOUT * 1000, QSPI_WAIT_BIT_SET); + } + + if (err) + { + goto _tx_dma_unmap; + } + + if ((err = k1x_qspi_readl_poll_tout(qspi, base + QSPI_SR, QSPI_SR_BUSY, + QSPI_WAIT_TIMEOUT * 1000, QSPI_WAIT_BIT_CLEAR))) + { + goto _tx_dma_unmap; + } + + /* Read RX buffer for IP command read */ + if (length && qxfer->parent.recv_buf) + { + k1x_qspi_read_rxfifo(qspi, qxfer); + } + + if (qspi->fr_error_flag & QSPI_FR_TBUF) + { + /* Abort current dma transfer */ + if (qspi->tx_dma_enable) + { + rt_dma_chan_stop(qspi->dma_tx); + } + + /* Clear TX buf */ + mcr = qspi_readl(qspi, qspi->io_map + QSPI_MCR); + mcr |= QSPI_MCR_CLR_TXF_MASK ; + qspi_writel(qspi, mcr, qspi->io_map + QSPI_MCR); + + /* Reduce tx unit size and retry */ + if (qspi->tx_dma_enable) + { + qspi->tx_unit_size = qspi->tx_buf_size; + } + + err = -RT_EIO; + } + else + { + if (qspi->tx_dma_enable) + { + qspi->tx_unit_size = qspi->tx_buf_size; + } + } + +_tx_dma_unmap: + if (qspi->tx_wmrk) + { + /* Disable TBFDE interrupt and dma unmap */ + k1x_qspi_disable_interrupt(qspi, QSPI_RSER_TBFDE); + qspi->tx_wmrk = 0; + } + + return err; +} + +static rt_bool_t is_read_from_cache_opcode(rt_uint8_t opcode) +{ + return ((opcode == READ_FROM_CACHE_OP) || + (opcode == READ_FROM_CACHE_OP_Fast) || + (opcode == READ_FROM_CACHE_OP_X2) || + (opcode == READ_FROM_CACHE_OP_X4) || + (opcode == READ_FROM_CACHE_OP_DUALIO) || + (opcode == READ_FROM_CACHE_OP_QUADIO)); +} + +static rt_err_t k1x_qspi_configure(struct rt_spi_device *device, + struct rt_spi_configuration *conf) +{ + return RT_EOK; +} + +static rt_ssize_t k1x_qspi_xfer(struct rt_spi_device *device, + struct rt_spi_message *xfer) +{ + void *base; + rt_err_t err = RT_EOK; + rt_uint32_t mask, reg; + struct k1x_qspi *qspi = raw_to_k1x_qspi(device->bus); + struct rt_qspi_message *qxfer = rt_container_of(xfer, struct rt_qspi_message, parent); + + base = qspi->io_map; + + /* Wait for controller being ready */ + mask = QSPI_SR_BUSY | QSPI_SR_IP_ACC_MASK | QSPI_SR_AHB_ACC_MASK; + if ((err = k1x_qspi_readl_poll_tout(qspi, + base + QSPI_SR, mask, QSPI_WAIT_TIMEOUT * 1000, QSPI_WAIT_BIT_CLEAR))) + { + LOG_E("Controller not ready"); + return err; + } + + /* Clear TX/RX buffer before transaction */ + reg = qspi_readl(qspi, base + QSPI_MCR); + reg |= QSPI_MCR_CLR_TXF_MASK | QSPI_MCR_CLR_RXF_MASK; + qspi_writel(qspi, reg, base + QSPI_MCR); + + /* + * Reset the sequence pointers whenever the sequence ID is changed by + * updating the SEDID filed in QSPI_IPCR OR QSPI_BFGENCR. + */ + reg = qspi_readl(qspi, base + QSPI_SPTRCLR); + reg |= (QSPI_SPTRCLR_IPPTRC | QSPI_SPTRCLR_BFPTRC); + qspi_writel(qspi, reg, base + QSPI_SPTRCLR); + + /* Set the flash address into the QSPI_SFAR */ + qspi_write_sfar(qspi, qspi->memmap_base + qxfer->address.content); + + /* Clear QSPI_FR before trigger LUT command */ + if ((reg = qspi_readl(qspi, base + QSPI_FR))) + { + qspi_writel(qspi, reg, base + QSPI_FR); + } + qspi->fr_error_flag = 0; + + /* + * Read page command 13h must be done by IP command. + * read from cache through the AHB bus by accessing the mapped memory. + * In all other cases we use IP commands to access the flash. + */ + if (xfer->length > (qspi->rx_buf_size - 4) && + xfer->recv_buf && qspi->ahb_read_enable && + is_read_from_cache_opcode(qxfer->instruction.content)) + { + k1x_qspi_prepare_lut(qspi, qxfer, SEQID_LUT_AHBREAD_ID); + err = k1x_qspi_ahb_read(qspi, qxfer); + } + else + { + /* IP command */ + k1x_qspi_prepare_lut(qspi, qxfer, SEQID_LUT_SHARED_ID); + + if (xfer->length && xfer->send_buf) + { + err = k1x_qspi_fill_txfifo(qspi, qxfer); + } + if (!err) + { + err = k1x_qspi_do_op(qspi, qxfer); + } + } + + /* Invalidate the data in the AHB buffer. */ + k1x_qspi_invalid(qspi); + + return err ? : xfer->length; +} + +static const struct rt_spi_ops k1x_qspi_ops = +{ + .configure = k1x_qspi_configure, + .xfer = k1x_qspi_xfer, +}; + +static void k1x_qspi_isr(int irq, void *param) +{ + rt_uint32_t fr; + struct k1x_qspi *qspi = param; + + /* Disable all interrupts */ + qspi_writel(qspi, 0, qspi->io_map + QSPI_RSER); + + fr = qspi_readl(qspi, qspi->io_map + QSPI_FR); + + /* Check QSPI_FR error flag */ + if (fr & (COMMAND_FR_FLAG | BUFFER_FR_FLAG)) + { + qspi->fr_error_flag = fr & (COMMAND_FR_FLAG | BUFFER_FR_FLAG); + + if (fr & QSPI_FR_IPGEF) + { + LOG_E("IP command trigger during AHB grant"); + } + if (fr & QSPI_FR_IPIEF) + { + LOG_E("IP command trigger could not be executed"); + } + if (fr & QSPI_FR_IPAEF) + { + LOG_E("IP command trigger during AHB access"); + } + if (fr & QSPI_FR_IUEF) + { + LOG_E("IP command usage error"); + } + if (fr & QSPI_FR_AIBSEF) + { + LOG_E("AHB illegal burst size error"); + } + if (fr & QSPI_FR_AITEF) + { + LOG_E("AHB illegal transaction error"); + } + if (fr & QSPI_FR_ABSEF) + { + LOG_E("AHB sequence error"); + } + + if (fr & QSPI_FR_TBUF) + { + /* Disable TBFDE interrupt */ + k1x_qspi_disable_interrupt(qspi, QSPI_RSER_TBFDE); + LOG_E("TX buffer underrun"); + } + if (fr & QSPI_FR_RBOF) + { + LOG_E("RX buffer overflow"); + } + if (fr & QSPI_FR_ABOF) + { + LOG_E("AHB buffer overflow"); + } + } + + if (qspi->cmd_interrupt && (fr & (QSPI_FR_TFF_MASK | COMMAND_FR_FLAG | BUFFER_FR_FLAG))) + { + rt_completion_done(&qspi->cmd_completion); + } +} + +static void k1x_qspi_free(struct k1x_qspi *qspi, struct rt_device *dev) +{ + /* Set disable mode */ + qspi_writel(qspi, QSPI_MCR_MDIS_MASK, qspi->io_map + QSPI_MCR); + qspi_writel(qspi, 0x0, qspi->io_map + QSPI_RSER); + + if (qspi->io_map) + { + rt_iounmap(qspi->io_map); + } + + if (qspi->pmuap_addr) + { + rt_iounmap(qspi->pmuap_addr); + } + + if (!rt_is_err_or_null(qspi->dma_tx)) + { + rt_dma_chan_release(qspi->dma_tx); + } + + if (!rt_is_err_or_null(qspi->dma_rx)) + { + rt_dma_chan_release(qspi->dma_rx); + } + + if (!rt_is_err_or_null(qspi->rstc)) + { + rt_reset_control_assert(qspi->rstc); + rt_reset_control_put(qspi->rstc); + } + + if (!rt_is_err_or_null(qspi->clk)) + { + rt_clk_disable_unprepare(qspi->clk); + rt_clk_put(qspi->clk); + } + + if (!rt_is_err_or_null(qspi->bus_clk)) + { + rt_clk_disable_unprepare(qspi->bus_clk); + rt_clk_put(qspi->bus_clk); + } + + rt_free(qspi); +} + +static rt_err_t k1x_qspi_probe(struct rt_platform_device *pdev) +{ + void *base; + rt_err_t err; + rt_uint32_t reg; + const char *bus_name; + rt_uint64_t addr, size; + rt_uint32_t qspi_bus_num = 0; + struct rt_device *dev = &pdev->parent; + struct k1x_qspi *qspi = rt_calloc(1, sizeof(*qspi)); + + if (!qspi) + { + return -RT_ENOMEM; + } + + if (!(qspi->io_map = rt_dm_dev_iomap_by_name(dev, "qspi-base"))) + { + err = -RT_EIO; + goto _fail; + } + qspi->io_phys = (rt_ubase_t)rt_kmem_v2p(qspi->io_map); + + if ((err = rt_dm_dev_get_address_by_name(dev, "qspi-mmap", &addr, &size))) + { + err = -RT_EIO; + goto _fail; + } + qspi->ahb_map = rt_ioremap((void *)addr, size); + qspi->memmap_base = addr; + qspi->memmap_size = size; + + if ((qspi->irq = rt_dm_dev_get_irq(dev, 0)) < 0) + { + err = qspi->irq; + goto _fail; + } + + if ((err = rt_dm_dev_prop_read_u32(dev, "k1x,qspi-freq", &qspi->max_hz))) + { + goto _fail; + } + + if (rt_dm_dev_prop_read_u32(dev, "k1x,qspi-sfa1ad", &qspi->sfa1ad)) + { + qspi->sfa1ad = QSPI_FLASH_A1_TOP(qspi); + } + else + { + qspi->sfa1ad += qspi->memmap_base; + } + if (rt_dm_dev_prop_read_u32(dev, "k1x,qspi-sfa2ad", &qspi->sfa2ad)) + { + qspi->sfa2ad = QSPI_FLASH_A2_TOP(qspi); + } + else + { + qspi->sfa2ad += qspi->sfa1ad; + } + if (rt_dm_dev_prop_read_u32(dev, "k1x,qspi-sfb1ad", &qspi->sfb1ad)) + { + qspi->sfb1ad = QSPI_FLASH_B1_TOP(qspi); + } + else + { + qspi->sfb1ad = qspi->sfa2ad; + } + if (rt_dm_dev_prop_read_u32(dev, "k1x,qspi-sfb2ad", &qspi->sfb2ad)) + { + qspi->sfb2ad = QSPI_FLASH_B2_TOP(qspi); + } + else + { + qspi->sfb2ad += qspi->sfb1ad; + } + + /* map QSPI PMUap register address */ + if (rt_dm_dev_prop_read_u32(dev, "k1x,qspi-pmuap-reg", &qspi->pmuap_reg)) + { + qspi->pmuap_reg = PMUA_QSPI_CLK_RES_CTRL; + } + qspi->pmuap_addr = rt_ioremap((void *)(rt_ubase_t)qspi->pmuap_reg, 4); + + if (rt_dm_dev_prop_read_u32(dev, "k1x,qspi-mpmu-acgr-reg", &qspi->mpmu_acgr_reg)) + { + qspi->mpmu_acgr_reg = K1X_MPMU_ACGR; + } + qspi->mpmu_acgr = rt_ioremap((void *)(rt_ubase_t)qspi->mpmu_acgr_reg, 4); + + if (rt_dm_dev_prop_read_u32(dev, "k1x,qspi-rx-buf", &qspi->rx_buf_size)) + { + qspi->rx_buf_size = QSPI_RX_BUFF_MAX; + } + + if (rt_dm_dev_prop_read_u32(dev, "k1x,qspi-tx-buf", &qspi->tx_buf_size)) + { + qspi->tx_buf_size = QSPI_TX_BUFF_MAX; + } + + if (rt_dm_dev_prop_read_u32(dev, "k1x,qspi-ahb-buf", &qspi->ahb_buf_size)) + { + qspi->ahb_buf_size = QSPI_AHB_BUFF_MAX_SIZE; + } + + if (rt_dm_dev_prop_read_u32(dev, "k1x,qspi-ahb-enable", &qspi->ahb_read_enable)) + { + qspi->ahb_read_enable = 1; + } + + if (rt_dm_dev_prop_read_u32(dev, "k1x,qspi-interrupt", &qspi->cmd_interrupt)) + { + qspi->cmd_interrupt = 1; + } + + if (rt_dm_dev_prop_read_u32(dev, "k1x,qspi-endian-xchg", &qspi->endian_xchg)) + { + qspi->endian_xchg = 0; + } + + if (rt_dm_dev_prop_read_u32(dev, "k1x,qspi-cs", &qspi->cs_selected)) + { + qspi->cs_selected = QSPI_DEFAULT_CS; + } + + if (rt_dm_dev_prop_read_u32(dev, "k1x,qspi-tx-dma", &qspi->tx_dma_enable)) + { + qspi->tx_dma_enable = 0; + } + + if (rt_dm_dev_prop_read_u32(dev, "k1x,qspi-rx-dma", &qspi->rx_dma_enable)) + { + qspi->rx_dma_enable = 0; + } + + rt_dm_dev_prop_read_u32(dev, "k1x,qspi-id", &qspi_bus_num); + + /* Prepare DMA */ + if (qspi->rx_dma_enable) + { + qspi->dma_rx = rt_dma_chan_request(dev, RT_NULL); + + if (!rt_is_err_or_null(qspi->dma_rx)) + { + qspi->dma_rx->callback = k1x_qspi_dma_callback; + + qspi->rx_config.direction = RT_DMA_MEM_TO_MEM; + qspi->rx_config.src_addr = qspi->memmap_base; + + qspi->rx_transfer.src_addr = qspi->rx_config.src_addr; + } + else + { + qspi->dma_rx = RT_NULL; + qspi->rx_dma_enable = 0; + } + } + + if (qspi->tx_dma_enable) + { + qspi->dma_tx = rt_dma_chan_request(dev, "tx-dma"); + + if (!rt_is_err_or_null(qspi->dma_tx)) + { + qspi->dma_tx->callback = k1x_qspi_dma_callback; + + qspi->tx_config.direction = RT_DMA_MEM_TO_DEV; + qspi->tx_config.dst_addr_width = RT_DMA_SLAVE_BUSWIDTH_4_BYTES; + qspi->tx_config.dst_addr = qspi->io_phys + QSPI_TBDR - 4; + qspi->tx_config.dst_maxburst = QSPI_TX_DMA_BURST; + + qspi->tx_transfer.dst_addr = qspi->tx_config.dst_addr; + } + else + { + qspi->dma_tx = RT_NULL; + qspi->tx_dma_enable = 0; + } + } + + if (qspi->dma_tx || qspi->dma_rx) + { + rt_completion_init(&qspi->dma_completion); + } + + if (qspi->tx_dma_enable) + { + qspi->tx_unit_size = qspi->tx_buf_size; + } + else + { + qspi->tx_unit_size = qspi->tx_buf_size; + } + + if (qspi->ahb_read_enable) + { + qspi->rx_unit_size = 4 * SIZE_KB; + } + else + { + qspi->rx_unit_size = qspi->rx_buf_size; + } + + /* QSPI init start */ + base = qspi->io_map; + + qspi->rstc = rt_reset_control_get_by_index(dev, 0); + if (rt_is_err(qspi->rstc)) + { + err = rt_ptr_err(qspi->rstc); + goto _fail; + } + + rt_reset_control_assert(qspi->rstc); + + /* Set PMUap */ + qspi->clk = rt_clk_get_by_name(dev, "qspi_clk"); + if (rt_is_err(qspi->clk)) + { + err = rt_ptr_err(qspi->clk); + goto _fail; + } + + qspi->bus_clk = rt_clk_get_by_name(dev, "qspi_bus_clk"); + if (rt_is_err(qspi->bus_clk)) + { + err = rt_ptr_err(qspi->bus_clk); + goto _fail; + } + + if ((err = rt_clk_set_rate(qspi->clk, qspi->max_hz))) + { + LOG_E("Fail to set clk"); + goto _fail; + } + + if ((err = rt_clk_prepare_enable(qspi->clk))) + { + LOG_E("Fail to enable clk"); + goto _fail; + } + + rt_clk_prepare_enable(qspi->bus_clk); + + rt_reset_control_deassert(qspi->rstc); + + /* Rest qspi */ + qspi_reset(qspi); + + /* Clock settings */ + qspi_enter_mode(qspi, QSPI_DISABLE_MODE); + + /* Sampled by sfif_clk_b; half cycle delay; */ + if (qspi->max_hz < (QSPI_SMPR_FSPHS_CLK >> 2)) + { + qspi_writel(qspi, 0x0, base + QSPI_SMPR); + } + else + { + qspi_writel(qspi, QSPI_SMPR_FSPHS_MASK, base + QSPI_SMPR); + } + + /* Fix wirte failure issue*/ + qspi_writel(qspi, 0x8, base + QSPI_SOCCR); + + /* Set the default source address QSPI_AMBA_BASE*/ + qspi_write_sfar(qspi, qspi->memmap_base); + qspi_writel(qspi, 0x0, base + QSPI_SFACR); + + /* Config ahb read start */ + /* Disable BUF0~BUF1, use BUF3 for all masters */ + qspi_writel(qspi, 0, base + QSPI_BUF0IND); + qspi_writel(qspi, 0, base + QSPI_BUF1IND); + qspi_writel(qspi, 0, base + QSPI_BUF2IND); + + /* AHB Master port */ + qspi_writel(qspi, 0xe, base + QSPI_BUF0CR); + qspi_writel(qspi, 0xe, base + QSPI_BUF1CR); + qspi_writel(qspi, 0xe, base + QSPI_BUF2CR); + qspi_writel(qspi, + QSPI_BUF3CR_ALLMST_MASK | QSPI_BUF3CR_ADATSZ((qspi->ahb_buf_size / 8)), + base + QSPI_BUF3CR); + + /* Set AHB read sequence id */ + qspi_writel(qspi, + QSPI_BFGENCR_SEQID(SEQID_LUT_AHBREAD_ID), + base + QSPI_BFGENCR); + /* Config ahb read end */ + + /* Set flash memory map */ + qspi_writel(qspi, qspi->sfa1ad & 0xfffffc00, base + QSPI_SFA1AD); + qspi_writel(qspi, qspi->sfa2ad & 0xfffffc00, base + QSPI_SFA2AD); + qspi_writel(qspi, qspi->sfb1ad & 0xfffffc00, base + QSPI_SFB1AD); + qspi_writel(qspi, qspi->sfb2ad & 0xfffffc00, base + QSPI_SFB2AD); + + /* ISD3FB, ISD2FB, ISD3FA, ISD2FA = 1; END_CFG=0x3 */ + reg = qspi_readl(qspi, base + QSPI_MCR); + reg |= QSPI_MCR_END_CFG_MASK | QSPI_MCR_ISD_MASK; + qspi_writel(qspi, reg, base + QSPI_MCR); + + /* Module enabled */ + qspi_enter_mode(qspi, QSPI_NORMAL_MODE); + + /* Read using the IP Bus registers QSPI_RBDR0 to QSPI_RBDR31*/ + qspi_write_rbct(qspi, QSPI_RBCT_RXBRD_MASK); + + /* Clear all interrupt status */ + qspi_writel(qspi, 0xffffffff, base + QSPI_FR); + /* QSPI init end */ + + rt_completion_init(&qspi->cmd_completion); + + dev->user_data = qspi; + + qspi->parent.parent.ofw_node = dev->ofw_node; + + rt_dm_dev_set_name(&qspi->parent.parent, "qspi%d", qspi_bus_num); + bus_name = rt_dm_dev_get_name(&qspi->parent.parent); + + rt_hw_interrupt_install(qspi->irq, k1x_qspi_isr, qspi, bus_name); + rt_hw_interrupt_umask(qspi->irq); + + if ((err = rt_qspi_bus_register(&qspi->parent, bus_name, &k1x_qspi_ops))) + { + goto _fail; + } + + return RT_EOK; +_fail: + k1x_qspi_free(qspi, dev); + + return err; +} + +static rt_err_t k1x_qspi_remove(struct rt_platform_device *pdev) +{ + struct rt_device *dev = &pdev->parent; + struct k1x_qspi *qspi = dev->user_data; + + rt_hw_interrupt_mask(qspi->irq); + rt_pic_detach_irq(qspi->irq, qspi); + + rt_device_unregister(&qspi->parent.parent); + + k1x_qspi_free(qspi, dev); + + return RT_EOK; +} + +static const struct rt_ofw_node_id k1x_qspi_ofw_ids[] = +{ + { .compatible = "spacemit,k1x-qspi", }, + { /* sentinel */ } +}; + +static struct rt_platform_driver k1x_qspi_driver = +{ + .name = "k1x-qspi", + .ids = k1x_qspi_ofw_ids, + + .probe = k1x_qspi_probe, + .remove = k1x_qspi_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(k1x_qspi_driver); diff --git a/bsp/spacemit/dm/spi/spi-k1x.c b/bsp/spacemit/dm/spi/spi-k1x.c new file mode 100644 index 000000000000..fbc7777b8974 --- /dev/null +++ b/bsp/spacemit/dm/spi/spi-k1x.c @@ -0,0 +1,1142 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include "dev_spi_dm.h" + +#define DBG_TAG "spi.k1x.spi" +#define DBG_LVL DBG_INFO +#include + +#include +#include +#include +#include + +/* Spacemit k1x SPI Registers */ +#define TOP_CTRL 0x00 /* SSP Top Control Register */ +#define FIFO_CTRL 0x04 /* SSP FIFO Control Register */ +#define INT_EN 0x08 /* SSP Interrupt Enable Register */ +#define TO 0x0c /* SSP Time Out Register */ +#define DATAR 0x10 /* SSP Data Register */ +#define STATUS 0x14 /* SSP Stauts Register */ +#define PSP_CTRL 0x18 /* SSP Programmable Serial Protocal Control Register */ +#define NET_WORK_CTRL 0x1c /* SSP NET Work Control Register */ +#define NET_WORK_STATUS 0x20 /* SSP Net Work Status Register */ +#define RWOT_CTRL 0x24 /* SSP RWOT Control Register */ +#define RWOT_CCM 0x28 /* SSP RWOT Counter Cycles Match Register */ +#define RWOT_CVWRn 0x2c /* SSP RWOT Counter Value Write for Read Request Register */ +#define CLK_PHASE_ADJ 0x30 /* SSP clock phase adjustment for debug */ + +/* 0x00 TOP_CTRL */ +#define TOP_TTELP RT_BIT(18) +#define TOP_TTE RT_BIT(17) +#define TOP_SCFR RT_BIT(16) +#define TOP_IFS RT_BIT(15) +#define TOP_HOLD_FRAME_LOW RT_BIT(14) +#define TOP_TRAIL RT_BIT(13) +#define TOP_LBM RT_BIT(12) +#define TOP_SPH RT_BIT(11) +#define TOP_SPO RT_BIT(10) +#define TOP_DSS(x) ((x - 1) << 5) +#define TOP_DSS_MASK (0x1f << 5) +#define TOP_SFRMDIR RT_BIT(4) +#define TOP_SCLKDIR RT_BIT(3) +#define TOP_FRF_MASK (0x3 << 1) +#define TOP_FRF_Motorola (0x0 << 1) /* Motorola's Serial Peripheral Interface (SPI) */ +#define TOP_FRF_TI (0x1 << 1) /* Texas Instruments' Synchronous Serial Protocol (SSP) */ +#define TOP_FRF_National (0x2 << 1) /* National Microwire */ +#define TOP_FRF_PSP (0x3 << 1) /* Programmable Serial Protocol(PSP) */ +#define TOP_SSE RT_BIT(0) + +/* 0x04 FIFO_CTRL */ +#define FIFO_STRF RT_BIT(19) +#define FIFO_EFWR RT_BIT(18) +#define FIFO_RXFIFO_AUTO_FULL_CTRL RT_BIT(17) +#define FIFO_FPCKE RT_BIT(16) +#define FIFO_TXFIFO_WR_ENDIAN_MASK (0x3 << 14) +#define FIFO_RXFIFO_RD_ENDIAN_MASK (0x3 << 12) +#define FIFO_WR_ENDIAN_16BITS RT_BIT(14) /* Swap first 16 bits and last 16 bits */ +#define FIFO_WR_ENDIAN_8BITS (2 << 14) /* Swap all 4 bytes */ +#define FIFO_RD_ENDIAN_16BITS RT_BIT(12) /* Swap first 16 bits and last 16 bits */ +#define FIFO_RD_ENDIAN_8BITS (2 << 12) /* Swap all 4 bytes */ +#define FIFO_RSRE RT_BIT(11) +#define FIFO_TSRE RT_BIT(10) + +/* 0x08 INT_EN */ +#define INT_EN_EBCEI RT_BIT(6) +#define INT_EN_TIM RT_BIT(5) +#define INT_EN_RIM RT_BIT(4) +#define INT_EN_TIE RT_BIT(3) +#define INT_EN_RIE RT_BIT(2) +#define INT_EN_TINTE RT_BIT(1) +#define INT_EN_PINTE RT_BIT(0) + +/* 0x0C TO */ +#define TIMEOUT(x) ((x) << 0) + +/* 0x10 DATAR */ +#define DATA(x) ((x) << 0) + +/* 0x14 STATUS */ +#define STATUS_OSS RT_BIT(23) +#define STATUS_TX_OSS RT_BIT(22) +#define STATUS_BCE RT_BIT(21) +#define STATUS_ROR RT_BIT(20) +#define STATUS_RNE RT_BIT(14) +#define STATUS_RFS RT_BIT(13) +#define STATUS_TUR RT_BIT(12) +#define STATUS_TNF RT_BIT(6) +#define STATUS_TFS RT_BIT(5) +#define STATUS_EOC RT_BIT(4) +#define STATUS_TINT RT_BIT(3) +#define STATUS_PINT RT_BIT(2) +#define STATUS_CSS RT_BIT(1) +#define STATUS_BSY RT_BIT(0) + +/* 0x18 PSP_CTRL */ +#define PSP_EDMYSTOP(x) ((x) << 27) +#define PSP_EMYSTOP(x) ((x) << 25) +#define PSP_EDMYSTRT(x) ((x) << 23) +#define PSP_DMYSTRT(x) ((x) << 21) +#define PSP_STRTDLY(x) ((x) << 18) +#define PSP_SFRMWDTH(x) ((x) << 12) +#define PSP_SFRMDLY(x) ((x) << 5) +#define PSP_SFRMP (1 << 4) +#define PSP_FSRT (1 << 3) +#define PSP_ETDS (1 << 2) +#define PSP_SCMODE(x) ((x) << 0) + +/* 0x1C NET_WORK_CTRL */ +#define RTSA(x) ((x) << 12) +#define RTSA_MASK (0xff << 12) +#define TTSA(x) ((x) << 4) +#define TTSA_MASK (0xff << 4) +#define NET_FRDC(x) ((x) << 1) +#define NET_WORK_MODE (1 << 0) + +/* 0x20 NET_WORK_STATUS */ +#define NET_SATUS_NMBSY (1 << 3) +#define NET_STATUS_TSS(x) ((x) << 0) + +/* 0x24 RWOT_CTRL */ +#define RWOT_MASK_RWOT_LAST_SAMPLE RT_BIT(4) +#define RWOT_CLR_RWOT_CYCLE RT_BIT(3) +#define RWOT_SET_RWOT_CYCLE RT_BIT(2) +#define RWOT_CYCLE_RWOT_EN RT_BIT(1) +#define RWOT_RWOT RT_BIT(0) + +#define TIMOUT_DFLT 3000 +#define TIMOUT_DFLT_SLAVE 0x40000 + +#define RX_THRESH_DFLT 9 +#define TX_THRESH_DFLT 8 +/* 0x14 */ +#define STATUS_TFL_MASK (0x1f << 7) /* Transmit FIFO Level mask */ +#define STATUS_RFL_MASK (0x1f << 15) /* Receive FIFO Level mask */ +/* 0x4 */ +#define FIFO_TFT (0x0000001f) /* Transmit FIFO Threshold (mask) */ +#define FIFO_TxTresh(x) (((x) - 1) << 0) /* level [1..32] */ +#define FIFO_RFT (0x000003e0) /* Receive FIFO Threshold (mask) */ +#define FIFO_RxTresh(x) (((x) - 1) << 5) /* level [1..32] */ +/* + * Select the right DMA implementation. + */ +#define MAX_DMA_LEN (512 * SIZE_KB) +#define DEFAULT_DMA_FIFO_CTRL (FIFO_TSRE | FIFO_RSRE) +#define DEFAULT_DMA_TOP_CTRL (TOP_TRAIL) + +struct k1x_spi; + +struct chip_data +{ + rt_uint32_t top_ctrl; + rt_uint32_t fifo_ctrl; + rt_uint32_t timeout; + rt_uint8_t n_bytes; + rt_uint32_t dma_burst_size; + rt_uint32_t threshold; + rt_uint32_t dma_threshold; + rt_uint8_t enable_dma; + rt_bool_t (*write)(struct k1x_spi *spi); + rt_bool_t (*read)(struct k1x_spi *spi); +}; + +struct k1x_spi +{ + struct rt_spi_bus parent; + + struct rt_clk *clk; + struct rt_reset_control *rstc; + + int irq; + void *ioaddr; + rt_uint32_t ssdr_physical; + rt_uint32_t max_speed_hz; + + /* SSP masks*/ + rt_uint32_t dma_fifo_ctrl; + rt_uint32_t dma_top_ctrl; + rt_uint32_t int_cr; + rt_uint32_t dma_cr; + rt_uint32_t clear_sr; + rt_uint32_t mask_sr; + + rt_bool_t enable_dma; + rt_atomic_t dma_running; + struct rt_dma_chan *rx_chan; + struct rt_dma_chan *tx_chan; + struct rt_dma_slave_config rx_config; + struct rt_dma_slave_config tx_config; + struct rt_dma_slave_transfer rx_transfer; + struct rt_dma_slave_transfer tx_transfer; + + rt_bool_t (*write)(struct k1x_spi *spi); + rt_bool_t (*read)(struct k1x_spi *spi); + void (*transfer_handler)(struct k1x_spi *spi); + + void *tx, *tx_end; + void *rx, *rx_end; + rt_uint8_t n_bytes; + struct rt_spi_message *cur_msg; + + struct chip_data cur_chip; + struct rt_completion cur_msg_completion; + + /* Support RX FIFO auto full control and endian swap */ + rt_bool_t slave_mode; + rt_uint32_t ssp_enhancement; + struct rt_timer slave_rx_timer; +}; + +#define raw_to_k1x_spi(raw) rt_container_of(raw, struct k1x_spi, parent) + +rt_inline rt_uint32_t k1x_spi_read(struct k1x_spi *spi, int reg) +{ + return HWREG32(spi->ioaddr + reg); +} + +rt_inline void k1x_spi_write(struct k1x_spi *spi, int reg, rt_uint32_t val) +{ + HWREG32(spi->ioaddr + reg) = val; +} + +static void k1x_spi_dma_transfer_complete(struct k1x_spi *spi, rt_bool_t error) +{ + if (!rt_atomic_dec_and_test(&spi->dma_running)) + { + return; + } + + /* + * If the other CPU is still handling the ROR interrupt we + * might not know about the error yet. So we re-check the + * ROR bit here before we clear the status register. + */ + if (!error) + { + rt_uint32_t status = k1x_spi_read(spi, STATUS) & spi->mask_sr; + + error = status & STATUS_ROR; + } + + /* Clear status & disable interrupts */ + k1x_spi_write(spi, FIFO_CTRL, k1x_spi_read(spi, FIFO_CTRL) & ~spi->dma_fifo_ctrl); + k1x_spi_write(spi, TOP_CTRL, k1x_spi_read(spi, TOP_CTRL) & ~spi->dma_top_ctrl); + k1x_spi_write(spi, STATUS, spi->clear_sr); + k1x_spi_write(spi, TO, 0); + + if (error) + { + /* In case we got an error we disable the SSP now */ + k1x_spi_write(spi, TOP_CTRL, k1x_spi_read(spi, TOP_CTRL) & ~TOP_SSE); + } +} + +static void k1x_spi_dma_callback(struct rt_dma_chan *chan, rt_size_t size) +{ + struct k1x_spi *spi = chan->priv; + + k1x_spi_dma_transfer_complete(spi, RT_FALSE); +} + +static void k1x_spi_dma_transfer(struct k1x_spi *spi) +{ + rt_uint32_t status; + + status = k1x_spi_read(spi, STATUS) & spi->mask_sr; + + if ((spi->slave_mode && status & STATUS_TINT) || (status & STATUS_ROR)) + { + if (spi->rx) + { + rt_dma_chan_stop(spi->rx_chan); + } + if (spi->tx) + { + rt_dma_chan_stop(spi->tx_chan); + } + k1x_spi_dma_transfer_complete(spi, RT_TRUE); + } +} + +static rt_err_t k1x_spi_set_dma_burst_and_threshold(struct chip_data *chip, + struct rt_spi_device *device, + rt_uint8_t bits_per_word, rt_uint32_t *burst_code, rt_uint32_t *threshold) +{ + /* + * If the DMA burst size is given in chip_info we use + * that, otherwise we set it to half of FIFO size; SPI + * FIFO has 16 entry, so FIFO size = 16*bits_per_word/8; + * Also we use the default FIFO thresholds for now. + */ + if (chip && chip->dma_burst_size) + { + *burst_code = chip->dma_burst_size; + } + else if (bits_per_word <= 8) + { + *burst_code = 8; + } + else if (bits_per_word <= 16) + { + *burst_code = 16; + } + else + { + *burst_code = 32; + } + + *threshold = FIFO_RxTresh(RX_THRESH_DFLT) | FIFO_TxTresh(TX_THRESH_DFLT); + + return RT_EOK; +} + +static rt_bool_t k1x_spi_txfifo_full(struct k1x_spi *spi) +{ + return !(k1x_spi_read(spi, STATUS) & STATUS_TNF); +} + +/* Clear all rx fifo useless data */ +static int k1x_spi_flush(struct k1x_spi *spi) +{ + unsigned long limit = RT_TICK_PER_SECOND << 1; + + do { + while (k1x_spi_read(spi, STATUS) & STATUS_RNE) + { + k1x_spi_read(spi, DATAR); + } + } while ((k1x_spi_read(spi, STATUS) & STATUS_BSY) && --limit); + + k1x_spi_write(spi, STATUS, STATUS_ROR); + + return limit; +} + +static rt_bool_t null_writer(struct k1x_spi *spi) +{ + rt_uint8_t n_bytes = spi->n_bytes; + + if (k1x_spi_txfifo_full(spi) || spi->tx == spi->tx_end) + { + return RT_FALSE; + } + + k1x_spi_write(spi, DATAR, 0); + spi->tx += n_bytes; + + return RT_TRUE; +} + +static rt_bool_t null_reader(struct k1x_spi *spi) +{ + rt_uint8_t n_bytes = spi->n_bytes; + + while ((k1x_spi_read(spi, STATUS) & STATUS_RNE) && (spi->rx < spi->rx_end)) + { + k1x_spi_read(spi, DATAR); + spi->rx += n_bytes; + } + + return spi->rx == spi->rx_end; +} + +static rt_bool_t u8_writer(struct k1x_spi *spi) +{ + if (k1x_spi_txfifo_full(spi) || spi->tx == spi->tx_end) + { + return RT_FALSE; + } + + k1x_spi_write(spi, DATAR, *(rt_uint8_t *)(spi->tx)); + ++spi->tx; + + return RT_TRUE; +} + +static rt_bool_t u8_reader(struct k1x_spi *spi) +{ + while ((k1x_spi_read(spi, STATUS) & STATUS_RNE) && spi->rx < spi->rx_end) + { + *(rt_uint8_t *)(spi->rx) = k1x_spi_read(spi, DATAR); + ++spi->rx; + } + + return spi->rx == spi->rx_end; +} + +static rt_bool_t u16_writer(struct k1x_spi *spi) +{ + if (k1x_spi_txfifo_full(spi) || spi->tx == spi->tx_end) + { + return RT_FALSE; + } + + k1x_spi_write(spi, DATAR, *(rt_uint16_t *)(spi->tx)); + spi->tx += 2; + + return RT_TRUE; +} + +static rt_bool_t u16_reader(struct k1x_spi *spi) +{ + while ((k1x_spi_read(spi, STATUS) & STATUS_RNE) && spi->rx < spi->rx_end) + { + *(rt_uint16_t *)(spi->rx) = k1x_spi_read(spi, DATAR); + spi->rx += 2; + } + + return spi->rx == spi->rx_end; +} + +static rt_bool_t u32_writer(struct k1x_spi *spi) +{ + if (k1x_spi_txfifo_full(spi) || spi->tx == spi->tx_end) + { + return RT_FALSE; + } + + k1x_spi_write(spi, DATAR, *(rt_uint32_t *)(spi->tx)); + spi->tx += 4; + + return RT_TRUE; +} + +static rt_bool_t u32_reader(struct k1x_spi *spi) +{ + while ((k1x_spi_read(spi, STATUS) & STATUS_RNE) && spi->rx < spi->rx_end) + { + *(rt_uint32_t *)(spi->rx) = k1x_spi_read(spi, DATAR); + spi->rx += 4; + } + + return spi->rx == spi->rx_end; +} + +static void reset_fifo_ctrl(struct k1x_spi *spi) +{ + rt_uint32_t fifo_ctrl = 0; + struct chip_data *chip = &spi->cur_chip; + + fifo_ctrl |= chip->threshold; + k1x_spi_write(spi, FIFO_CTRL, fifo_ctrl); +} + +static void int_transfer_stop(struct k1x_spi *spi) +{ + rt_uint32_t int_en = 0; + + /* Stop SSP */ + k1x_spi_write(spi, STATUS, spi->clear_sr); + reset_fifo_ctrl(spi); + + int_en = k1x_spi_read(spi, INT_EN); + int_en &= ~spi->int_cr; + k1x_spi_write(spi, INT_EN, int_en); + + k1x_spi_write(spi, TO, 0); +} + +static void interrupt_transfer(struct k1x_spi *spi) +{ + rt_uint32_t irq_mask, irq_status; + + irq_mask = (k1x_spi_read(spi, INT_EN) & INT_EN_TIE) ? + spi->mask_sr : spi->mask_sr & ~STATUS_TFS; + irq_status = k1x_spi_read(spi, STATUS) & irq_mask; + + if (irq_status & STATUS_ROR) + { + /* Stop and rstc SSP */ + int_transfer_stop(spi); + k1x_spi_flush(spi); + k1x_spi_write(spi, TOP_CTRL, k1x_spi_read(spi, TOP_CTRL) & ~(TOP_SSE | TOP_HOLD_FRAME_LOW)); + return; + } + + if (irq_status & STATUS_TINT) + { + k1x_spi_write(spi, STATUS, STATUS_TINT); + + if (spi->read(spi)) + { + int_transfer_stop(spi); + return; + } + } + + /* Drain rx fifo, Fill tx fifo and prevent overruns */ + do { + if (spi->read(spi)) + { + int_transfer_stop(spi); + return; + } + } while (spi->write(spi)); + + if (spi->read(spi)) + { + int_transfer_stop(spi); + return; + } + + if (spi->tx == spi->tx_end) + { + rt_uint32_t int_en; + + int_en = k1x_spi_read(spi, INT_EN); + int_en &= ~INT_EN_TIE; + + k1x_spi_write(spi, INT_EN, int_en); + } +} + +static void slave_rx_timer_expired(void *param) +{ + struct k1x_spi *spi = param; + + if (spi->rx) + { + rt_dma_chan_stop(spi->rx_chan); + } + if (spi->tx) + { + rt_dma_chan_stop(spi->tx_chan); + } + k1x_spi_dma_transfer_complete(spi, RT_TRUE); +} + +static rt_err_t k1x_spi_spi_configure(struct rt_spi_device *device, + struct rt_spi_configuration *conf) +{ + rt_uint32_t tx_thres, rx_thres; + struct k1x_spi *spi = raw_to_k1x_spi(device->bus); + struct chip_data *chip = &spi->cur_chip; + + tx_thres = TX_THRESH_DFLT; + rx_thres = RX_THRESH_DFLT; + + chip->top_ctrl = 0; + chip->fifo_ctrl = 0; + chip->enable_dma = spi->enable_dma; + + if (spi->slave_mode) + { + chip->dma_burst_size = 32; + } + + if (chip->enable_dma) + { + /* Set up legal burst and threshold for dma */ + if (k1x_spi_set_dma_burst_and_threshold(chip, device, + device->config.data_width, &chip->dma_burst_size, &chip->dma_threshold)) + { + LOG_W("DMA burst size reduced to match bits_per_word"); + } + } + chip->threshold = (FIFO_RxTresh(rx_thres) & FIFO_RFT) | (FIFO_TxTresh(tx_thres) & FIFO_TFT); + + chip->top_ctrl &= ~(TOP_SPO | TOP_SPH); + chip->top_ctrl |= (((device->config.mode & RT_SPI_CPHA) != 0) ? TOP_SPH : 0) + | (((device->config.mode & RT_SPI_CPOL) != 0) ? TOP_SPO : 0); + + /* Enable rx fifo auto full control */ + if (spi->ssp_enhancement) + { + chip->fifo_ctrl |= FIFO_RXFIFO_AUTO_FULL_CTRL; + } + + if (device->config.data_width <= 8) + { + chip->n_bytes = 1; + chip->read = u8_reader; + chip->write = u8_writer; + } + else if (device->config.data_width <= 16) + { + chip->n_bytes = 2; + chip->read = u16_reader; + chip->write = u16_writer; + } + else if (device->config.data_width <= 32) + { + chip->n_bytes = 4; + chip->read = u32_reader; + chip->write = u32_writer; + } + + if (rt_clk_get_rate(spi->clk) != spi->max_speed_hz) + { + rt_clk_set_rate(spi->clk, spi->max_speed_hz); + } + + return RT_EOK; +} + +static rt_ssize_t k1x_spi_spi_xfer(struct rt_spi_device *device, + struct rt_spi_message *msg) +{ + rt_err_t err; + rt_uint8_t bits = 0; + rt_uint32_t top_ctrl, fifo_ctrl, int_en = 0, dma_thresh, dma_burst; + struct k1x_spi *spi = raw_to_k1x_spi(device->bus); + struct chip_data *chip = &spi->cur_chip; + + dma_thresh = chip->dma_threshold; + dma_burst = chip->dma_burst_size; + + if (spi->slave_mode) + { + rt_tick_t tick = rt_tick_from_millisecond(1000); + + rt_timer_control(&spi->slave_rx_timer, RT_TIMER_CTRL_SET_TIME, &tick); + + rt_timer_start(&spi->slave_rx_timer); + } + + /* Setup the transfer state based on the type of transfer */ + if (k1x_spi_flush(spi) == 0) + { + rt_timer_stop(&spi->slave_rx_timer); + + LOG_E("Flush failed"); + return -RT_EIO; + } + + if (device->config.max_hz && device->config.max_hz != rt_clk_get_rate(spi->clk)) + { + rt_clk_set_rate(spi->clk, device->config.max_hz); + } + + spi->n_bytes = chip->n_bytes; + spi->tx = (void *)msg->send_buf; + spi->tx_end = spi->tx + msg->length; + spi->rx = msg->recv_buf; + spi->rx_end = spi->rx + msg->length; + spi->write = spi->tx ? chip->write : null_writer; + spi->read = spi->rx ? chip->read : null_reader; + spi->cur_msg = msg; + + /* Change speed and bit per word on a per transfer */ + bits = device->config.data_width; + + if (bits <= 8) + { + spi->n_bytes = 1; + spi->read = spi->read != null_reader ? u8_reader : null_reader; + spi->write = spi->write != null_writer ? u8_writer : null_writer; + } + else if (bits <= 16) + { + spi->n_bytes = 2; + spi->read = spi->read != null_reader ? u16_reader : null_reader; + spi->write = spi->write != null_writer ? u16_writer : null_writer; + } + else if (bits <= 32) + { + spi->n_bytes = 4; + spi->read = spi->read != null_reader ? u32_reader : null_reader; + spi->write = spi->write != null_writer ? u32_writer : null_writer; + } + + /* + * If bits/word is changed in dma mode, then must check the + * thresholds and burst also + */ + if (chip->enable_dma) + { + if (k1x_spi_set_dma_burst_and_threshold(chip, + device, bits, &dma_burst, &dma_thresh)) + { + LOG_W("DMA burst size reduced to match bits_per_word"); + } + } + + /* + * Configure topctrl: + * set Motorola Frame Format + * set DSS + */ + top_ctrl = TOP_FRF_Motorola | TOP_DSS(bits); + LOG_D("%u Hz, %s", spi->max_speed_hz, chip->enable_dma ? "DMA" : "PIO"); + + top_ctrl |= chip->top_ctrl; + fifo_ctrl = chip->fifo_ctrl; + + if (spi->ssp_enhancement) + { + /* + * If transfer length is times of 4, then use + * 32 bit fifo width with endian swap support + */ + if (msg->length % 4 == 0 && bits <= 16) + { + if (bits <= 8) + { + fifo_ctrl |= FIFO_WR_ENDIAN_8BITS | FIFO_RD_ENDIAN_8BITS; + } + else if (bits <= 16) + { + fifo_ctrl |= FIFO_WR_ENDIAN_16BITS | FIFO_RD_ENDIAN_16BITS; + } + + bits = 32; + spi->n_bytes = 4; + if (msg->recv_buf) + { + spi->read = u32_reader; + } + if (msg->send_buf) + { + spi->write = u32_writer; + } + + if (chip->enable_dma) + { + if (k1x_spi_set_dma_burst_and_threshold(chip, + device, bits, &dma_burst, &dma_thresh)) + { + LOG_W("DMA burst size reduced to match bits_per_word"); + } + } + + top_ctrl &= ~TOP_DSS_MASK; + top_ctrl |= TOP_DSS(32); + } + } + + /* Check DMA is possible */ + if (msg->length <= MAX_DMA_LEN) + { + enum rt_dma_slave_buswidth width; + + /* Ensure we have the correct interrupt handler */ + spi->transfer_handler = k1x_spi_dma_transfer; + + switch (spi->n_bytes) + { + case 1: + width = RT_DMA_SLAVE_BUSWIDTH_1_BYTE; + break; + case 2: + width = RT_DMA_SLAVE_BUSWIDTH_2_BYTES; + break; + default: + width = RT_DMA_SLAVE_BUSWIDTH_4_BYTES; + break; + } + + if (spi->rx) + { + spi->rx_config.dst_addr = (rt_ubase_t)rt_kmem_v2p(spi->rx); + spi->rx_config.dst_addr_width = width; + spi->rx_config.dst_maxburst = msg->length; + + if ((err = rt_dma_chan_config(spi->rx_chan, &spi->rx_config))) + { + return err; + } + + spi->rx_transfer.buffer_len = msg->length; + spi->rx_transfer.dst_addr = spi->rx_config.dst_addr; + + if ((err = rt_dma_prep_single(spi->rx_chan, &spi->rx_transfer))) + { + return err; + } + + if ((err = rt_dma_chan_start(spi->rx_chan))) + { + return err; + } + } + + if (spi->tx) + { + spi->tx_config.src_addr = (rt_ubase_t)rt_kmem_v2p(spi->tx); + spi->tx_config.src_addr_width = width; + spi->tx_config.src_maxburst = chip->dma_burst_size; + + if ((err = rt_dma_chan_config(spi->tx_chan, &spi->tx_config))) + { + return err; + } + + spi->tx_transfer.buffer_len = msg->length; + spi->tx_transfer.src_addr = spi->tx_config.src_addr; + + if ((err = rt_dma_prep_single(spi->tx_chan, &spi->tx_transfer))) + { + return err; + } + + if ((err = rt_dma_chan_start(spi->tx_chan))) + { + return err; + } + } + + /* Clear status and start DMA engine */ + fifo_ctrl |= chip->fifo_ctrl | dma_thresh | spi->dma_fifo_ctrl; + top_ctrl |= chip->top_ctrl | spi->dma_top_ctrl; + k1x_spi_write(spi, STATUS, spi->clear_sr); + + rt_atomic_store(&spi->dma_running, 1); + + int_en = k1x_spi_read(spi, INT_EN) | spi->dma_cr; + } + else + { + /* Ensure we have the correct interrupt handler */ + spi->transfer_handler = interrupt_transfer; + + fifo_ctrl = fifo_ctrl | chip->fifo_ctrl | chip->threshold; + int_en = k1x_spi_read(spi, INT_EN) | spi->int_cr; + k1x_spi_write(spi, STATUS, spi->clear_sr); + } + + k1x_spi_write(spi, TO, chip->timeout); + + if (spi->slave_mode) + { + top_ctrl |= TOP_SSE | TOP_SCLKDIR | TOP_SFRMDIR; + } + else + { + top_ctrl |= TOP_HOLD_FRAME_LOW; + } + + /* + * This part changed the logic + * 1. clear SSE + * 2. write TOP_CTRL and other register + * 3. set SSE in the end of this function + */ + top_ctrl &= ~TOP_SSE; + k1x_spi_write(spi, TOP_CTRL, top_ctrl); + k1x_spi_write(spi, FIFO_CTRL, fifo_ctrl); + k1x_spi_write(spi, INT_EN, int_en); + top_ctrl |= TOP_SSE; + k1x_spi_write(spi, TOP_CTRL, top_ctrl); + + rt_completion_wait(&spi->cur_msg_completion, RT_WAITING_FOREVER); + + /* Disable the SSP now */ + k1x_spi_write(spi, TOP_CTRL, k1x_spi_read(spi, TOP_CTRL) & ~(TOP_SSE | TOP_HOLD_FRAME_LOW)); + + return msg->length; +} + +static struct rt_spi_ops k1x_spi_spi_ops = +{ + .configure = k1x_spi_spi_configure, + .xfer = k1x_spi_spi_xfer, +}; + +static void k1x_spi_spi_isr(int irq, void *param) +{ + rt_uint32_t int_en, mask, isr; + struct k1x_spi *spi = param; + + /* + * If the device is not yet in RPM suspended state and we get an + * interrupt that is meant for another device, check if status bits + * are all set to one. That means that the device is already powered off. + */ + isr = k1x_spi_read(spi, STATUS); + if (isr == ~0) + { + return; + } + + int_en = k1x_spi_read(spi, INT_EN); + mask = spi->mask_sr; + + /* Ignore possible writes if we don't need to write */ + if (!(int_en & INT_EN_TIE)) + { + mask &= ~STATUS_TFS; + } + + /* Ignore RX timeout interrupt if it is disabled */ + if (!(int_en & INT_EN_TINTE)) + { + mask &= ~STATUS_TINT; + } + + if (!(isr & mask)) + { + return; + } + + if (!spi->cur_msg) + { + k1x_spi_write(spi, TOP_CTRL, + k1x_spi_read(spi, TOP_CTRL) & ~(TOP_SSE | TOP_HOLD_FRAME_LOW)); + k1x_spi_write(spi, INT_EN, + k1x_spi_read(spi, INT_EN) & ~spi->int_cr); + k1x_spi_write(spi, TO, 0); + k1x_spi_write(spi, STATUS, spi->clear_sr); + + LOG_E("Bad message state in interrupt handler"); + + /* Never fail */ + return; + } + + return spi->transfer_handler(spi); +} + +static void k1x_spi_free(struct k1x_spi *spi, struct rt_device *dev) +{ + if (!rt_is_err_or_null(spi->rstc)) + { + rt_reset_control_assert(spi->rstc); + rt_reset_control_put(spi->rstc); + } + + if (!rt_is_err_or_null(spi->clk)) + { + rt_clk_disable_unprepare(spi->clk); + rt_clk_put(spi->clk); + } + + if (!rt_is_err_or_null(spi->rx_chan)) + { + rt_dma_chan_release(spi->rx_chan); + } + + if (!rt_is_err_or_null(spi->tx_chan)) + { + rt_dma_chan_release(spi->tx_chan); + } +} + +static rt_err_t k1x_spi_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + rt_uint32_t value, bus_num; + const char *bus_name; + struct rt_device *dev = &pdev->parent; + struct k1x_spi *spi = rt_calloc(1, sizeof(*spi)); + + if (!spi) + { + return -RT_ENOMEM; + } + + if (!(spi->ioaddr = rt_dm_dev_iomap(dev, 0))) + { + err = -RT_EIO; + goto _fail; + } + spi->ssdr_physical = (rt_ubase_t)rt_kmem_v2p(spi->ioaddr) + DATAR; + + if ((spi->irq = rt_dm_dev_get_irq(dev, 0)) < 0) + { + err = spi->irq; + goto _fail; + } + + spi->clk = rt_clk_get_by_index(dev, 0); + if (rt_is_err(spi->clk)) + { + err = rt_ptr_err(spi->clk); + goto _fail; + } + + spi->rstc = rt_reset_control_get_by_index(dev, 0); + if (rt_is_err(spi->rstc)) + { + err = rt_ptr_err(spi->rstc); + goto _fail; + } + + spi->enable_dma = !rt_dm_dev_prop_read_bool(dev, "k1x,ssp-disable-dma"); + spi->ssp_enhancement = rt_dm_dev_prop_read_bool(dev, "k1x,ssp-enhancement"); + spi->slave_mode = rt_dm_dev_prop_read_bool(dev, "k1x,ssp-slave-mode"); + + if ((err = rt_dm_dev_prop_read_u32(dev, "k1x,ssp-clock-rate", &spi->max_speed_hz))) + { + goto _fail; + } + + spi->int_cr = INT_EN_TIE | INT_EN_RIE | INT_EN_TINTE; /* INT_EN */ + spi->dma_cr = spi->slave_mode ? INT_EN_TINTE : 0; + spi->clear_sr = STATUS_ROR | STATUS_TINT; + spi->mask_sr = STATUS_TINT | STATUS_RFS | STATUS_TFS | STATUS_ROR; + spi->dma_top_ctrl = DEFAULT_DMA_TOP_CTRL; + spi->dma_fifo_ctrl = DEFAULT_DMA_FIFO_CTRL; + + /* Setup DMA if requested */ + if (spi->enable_dma) + { + spi->tx_chan = rt_dma_chan_request(dev, "tx"); + + if (!rt_is_err_or_null(spi->tx_chan)) + { + spi->tx_chan->callback = k1x_spi_dma_callback; + + spi->tx_config.direction = RT_DMA_MEM_TO_DEV; + spi->tx_config.dst_addr = spi->ssdr_physical; + + spi->tx_transfer.dst_addr = spi->tx_config.dst_addr; + } + else + { + goto _fail; + } + + spi->rx_chan = rt_dma_chan_request(dev, "rx"); + + if (!rt_is_err_or_null(spi->rx_chan)) + { + spi->rx_chan->callback = k1x_spi_dma_callback; + + spi->rx_config.direction = RT_DMA_MEM_TO_DEV; + spi->rx_config.src_addr = spi->ssdr_physical; + + spi->rx_transfer.src_addr = spi->rx_config.src_addr; + } + else + { + goto _fail; + } + } + + rt_clk_set_rate(spi->clk, spi->max_speed_hz); + spi->max_speed_hz = rt_clk_get_rate(spi->clk); + + rt_clk_prepare_enable(spi->clk); + rt_reset_control_deassert(spi->rstc); + + bus_num = 0; + rt_dm_dev_prop_read_u32(dev, "k1x,ssp-id", &bus_num); + + if ((bus_num == 2 || bus_num == 3) && + rt_dm_dev_prop_read_bool(dev, "k1x,ssp-enable-clk-phase-adj")) + { + k1x_spi_write(spi, CLK_PHASE_ADJ, 0x1); + } + + /* Load default SSP configuration */ + k1x_spi_write(spi, TOP_CTRL, 0); + k1x_spi_write(spi, FIFO_CTRL, 0); + value = FIFO_RxTresh(RX_THRESH_DFLT) | FIFO_TxTresh(TX_THRESH_DFLT); + k1x_spi_write(spi, FIFO_CTRL, value); + value = TOP_FRF_Motorola | TOP_DSS(8); + k1x_spi_write(spi, TOP_CTRL, value); + k1x_spi_write(spi, TO, 0); + + k1x_spi_write(spi, PSP_CTRL, 0); + + rt_completion_init(&spi->cur_msg_completion); + + dev->user_data = spi; + + spi->parent.parent.ofw_node = dev->ofw_node; + + if (pdev->dev_id >= 0) + { + rt_dm_dev_set_name(&spi->parent.parent, "spi%u", pdev->dev_id); + } + else + { + if (bus_num >= 0) + { + rt_dm_dev_set_name(&spi->parent.parent, "spi%u", bus_num); + } + else + { + rt_dm_dev_set_name_auto(&spi->parent.parent, "spi"); + } + } + bus_name = rt_dm_dev_get_name(&spi->parent.parent); + + if (spi->slave_mode) + { + rt_timer_init(&spi->slave_rx_timer, bus_name, slave_rx_timer_expired, spi, + 0, RT_TIMER_FLAG_PERIODIC); + } + + rt_hw_interrupt_install(spi->irq, k1x_spi_spi_isr, spi, bus_name); + rt_hw_interrupt_umask(spi->irq); + + if ((err = rt_spi_bus_register(&spi->parent, bus_name, &k1x_spi_spi_ops))) + { + goto _free_irq; + } + + return RT_EOK; + +_free_irq: + rt_hw_interrupt_mask(spi->irq); + rt_pic_detach_irq(spi->irq, spi); + +_fail: + k1x_spi_free(spi, dev); + + return err; +} + +static rt_err_t k1x_spi_remove(struct rt_platform_device *pdev) +{ + struct rt_device *dev = &pdev->parent; + struct k1x_spi *spi = dev->user_data; + + rt_hw_interrupt_mask(spi->irq); + rt_pic_detach_irq(spi->irq, spi); + + rt_device_unregister(&spi->parent.parent); + + /* Disable the SSP at the peripheral and SOC level */ + k1x_spi_write(spi, TOP_CTRL, 0); + k1x_spi_write(spi, FIFO_CTRL, 0); + + k1x_spi_free(spi, dev); + + return RT_EOK; +} + +static const struct rt_ofw_node_id k1x_spi_ofw_ids[] = +{ + { .compatible = "spacemit,k1x-spi" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver k1x_spi_driver = +{ + .name = "k1x-spi", + .ids = k1x_spi_ofw_ids, + + .probe = k1x_spi_probe, + .remove = k1x_spi_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(k1x_spi_driver); diff --git a/bsp/spacemit/dm/thermal/Kconfig b/bsp/spacemit/dm/thermal/Kconfig new file mode 100644 index 000000000000..38ce5540f8a6 --- /dev/null +++ b/bsp/spacemit/dm/thermal/Kconfig @@ -0,0 +1,3 @@ +config RT_THERMAL_K1X + bool "Spacemit K1X" + default n diff --git a/bsp/spacemit/dm/thermal/SConscript b/bsp/spacemit/dm/thermal/SConscript new file mode 100644 index 000000000000..78fbfcc7fa8e --- /dev/null +++ b/bsp/spacemit/dm/thermal/SConscript @@ -0,0 +1,13 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_THERMAL_K1X']): + src += ['thermal-k1x.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/thermal/thermal-k1x.c b/bsp/spacemit/dm/thermal/thermal-k1x.c new file mode 100644 index 000000000000..58344f7f9f43 --- /dev/null +++ b/bsp/spacemit/dm/thermal/thermal-k1x.c @@ -0,0 +1,484 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include +#include + +#define DBG_TAG "thermal.k1x" +#define DBG_LVL DBG_INFO +#include + +#define BITS(_start, _end) ((RT_BIT(_end) - RT_BIT(_start)) + RT_BIT(_end)) + +#define MAX_SENSOR_NUMBER 5 +#define TEMPERATURE_OFFSET 278 + +#define REG_TSEN_INT_MASK 0x14 +#define TSEN_EMERGENT_INT_OFFSET 23 +#define REG_EMERGENT_REBOOT_TEMP_THR 0x68 +#define REG_EMERGENT_REBOOT_TEMP_THR_MSK 0xffff + +#define REG_TSEN_TIME_CTRL 0x0c +#define BITS_TIME_CTRL_MASK BITS(0, 23) +#define VALUE_FILTER_PERIOD (0x3000 << 8) +#define BITS_RST_ADC_CNT BITS(4, 7) +#define VALUE_WAIT_REF_CNT (0xf << 0) + +#define BIT_TSEN_RAW_SEL RT_BIT(7) +#define BIT_TEMP_MODE RT_BIT(3) +#define BIT_EN_SENSOR RT_BIT(0) +#define BITS_TSEN_SW_CTRL BITS(18, 21) +#define BITS_CTUNE BITS(8, 11) +#define REG_TSEN_PCTRL 0x00 + +#define REG_TSEN_PCTRL2 0x04 +#define BITS_SDM_CLK_SEL BITS(14, 15) +#define BITS_SDM_CLK_SEL_24M (0 << 14) + +#define TSEN_INT_MASK RT_BIT(0) +#define BIT_HW_AUTO_MODE RT_BIT(23) + +#define MAX_SENSOR_NUMBER 5 + +struct sensor_enable +{ + rt_uint32_t bjt_en; + rt_uint32_t offset; + rt_uint32_t bit_msk; + rt_uint32_t en_val; +}; + +struct sensor_data +{ + rt_uint32_t data_reg; + rt_uint32_t offset; + rt_uint32_t bit_msk; +}; + +struct sensor_thrsh +{ + rt_uint32_t temp_thrsh; + rt_uint32_t low_offset; + rt_uint32_t high_offset; +}; + +struct k1x_thermal_sensor_desc +{ + rt_uint32_t int_msk; + rt_uint32_t int_clr; + rt_uint32_t int_sta; + rt_uint32_t offset; + rt_uint32_t bit_msk; + struct sensor_enable se; + struct sensor_data sd; + struct sensor_thrsh sr; +}; + +struct k1x_thermal; + +struct k1x_thermal_sensor +{ + struct rt_thermal_zone_device parent; + + void *regs; + struct k1x_thermal_sensor_desc *desc; +}; + +#define raw_to_k1x_thermal_sensor(raw) rt_container_of(raw, struct k1x_thermal_sensor, parent) + +struct k1x_thermal +{ + int irq; + void *regs; + struct rt_clk *clk; + struct rt_reset_control *rstc; + + /* Sensor range */ + rt_uint32_t sr[2]; + struct k1x_thermal_sensor *sensors; +}; + +static rt_err_t k1x_thermal_get_temp(struct rt_thermal_zone_device *zdev, int *out_temp) +{ + struct k1x_thermal_sensor *sensor = raw_to_k1x_thermal_sensor(zdev); + struct k1x_thermal_sensor_desc *desc = sensor->desc; + + *out_temp = HWREG32(sensor->regs + desc->sd.data_reg); + *out_temp &= desc->sd.bit_msk; + *out_temp >>= desc->sd.offset; + *out_temp -= TEMPERATURE_OFFSET; + *out_temp *= 1000; + + return RT_EOK; +} + +static rt_err_t k1x_thermal_set_trips(struct rt_thermal_zone_device *zdev, + int low_temp, int high_temp) +{ + rt_uint32_t temp; + int over_thrsh = high_temp, under_thrsh = low_temp; + struct k1x_thermal_sensor *sensor = raw_to_k1x_thermal_sensor(zdev); + struct k1x_thermal_sensor_desc *desc = sensor->desc; + + /* Set overflow */ + over_thrsh /= 1000; + over_thrsh += TEMPERATURE_OFFSET; + + temp = HWREG32(sensor->regs + desc->sr.temp_thrsh); + temp &= ~0xffff0000; + temp |= (over_thrsh << desc->sr.high_offset); + HWREG32(sensor->regs + desc->sr.temp_thrsh) = temp; + + /* set underflow */ + if (low_temp < 0) + { + under_thrsh = 0; + } + + under_thrsh /= 1000; + under_thrsh += TEMPERATURE_OFFSET; + temp = HWREG32(sensor->regs + desc->sr.temp_thrsh); + temp &= ~0xffff; + temp |= (under_thrsh << desc->sr.low_offset); + HWREG32(sensor->regs + desc->sr.temp_thrsh) = temp; + + return RT_EOK; +} + +static const struct rt_thermal_zone_ops k1x_thermal_ops = +{ + .get_temp = k1x_thermal_get_temp, + .set_trips = k1x_thermal_set_trips, +}; + +static void k1x_thermal_isr(int irqno, void *param) +{ + rt_uint32_t status, msk; + struct k1x_thermal_sensor *sensor = param; + struct k1x_thermal_sensor_desc *desc = sensor->desc; + + /* Get the status */ + status = HWREG32(sensor->regs + desc->int_sta); + status &= desc->bit_msk; + + if (!status) + { + return; + } + + /* Then clear the pending */ + msk = HWREG32(sensor->regs + desc->int_clr); + msk |= status; + HWREG32(sensor->regs + desc->int_clr) = msk; + + rt_thermal_zone_device_update(&sensor->parent, RT_THERMAL_MSG_EVENT_UNSPECIFIED); +} + +static rt_err_t init_sensors(struct rt_device *dev, struct k1x_thermal *thermal, + struct k1x_thermal_sensor_desc *desc) +{ + rt_err_t err; + rt_uint32_t temp; + + /* Read the sensor range */ + err = rt_dm_dev_prop_read_u32_array_index(dev, "sensor_range", 0, 2, thermal->sr); + if (err < 0) + { + LOG_E("Get sensor range error"); + return err; + } + + if (thermal->sr[1] >= MAX_SENSOR_NUMBER) + { + LOG_E("Un-fitable sensor range"); + return -RT_EINVAL; + } + + /* First: disable all the interrupts */ + HWREG32(thermal->regs + REG_TSEN_INT_MASK) = 0xffffffff; + + /* + * Decrease filter period time from 0x4000 to 0x3000, that + * means decrease 1/4 ADC sampling time for each sensor. + */ + temp = HWREG32(thermal->regs + REG_TSEN_TIME_CTRL); + temp &= ~BITS_TIME_CTRL_MASK; + temp |= VALUE_FILTER_PERIOD; + temp |= BITS_RST_ADC_CNT; + temp |= VALUE_WAIT_REF_CNT; + HWREG32(thermal->regs + REG_TSEN_TIME_CTRL) = temp; + + /* + * Enable all sensors' auto mode, enable dither control, + * consecutive mode, and power up sensor. + */ + temp = HWREG32(thermal->regs + REG_TSEN_PCTRL); + temp |= BIT_TSEN_RAW_SEL | BIT_TEMP_MODE | BIT_EN_SENSOR; + temp &= ~BITS_TSEN_SW_CTRL; + temp &= ~BITS_CTUNE; + HWREG32(thermal->regs + REG_TSEN_PCTRL) = temp; + + /* Select 24M clk for high speed mode */ + temp = HWREG32(thermal->regs + REG_TSEN_PCTRL2); + temp &= ~BITS_SDM_CLK_SEL; + temp |= BITS_SDM_CLK_SEL_24M; + HWREG32(thermal->regs + REG_TSEN_PCTRL2) = temp; + + /* Enable the sensor interrupt */ + for (int i = thermal->sr[0]; i <= thermal->sr[1]; ++i) + { + struct sensor_enable *se = &desc[i].se; + + temp = HWREG32(thermal->regs + se->bjt_en); + temp &= ~se->bit_msk; + temp |= se->en_val << se->offset; + HWREG32(thermal->regs + se->bjt_en) = temp; + } + + return 0; +} + +static void enable_sensors(struct k1x_thermal *thermal) +{ + HWREG32(thermal->regs + REG_TSEN_INT_MASK) = + HWREG32(thermal->regs + REG_TSEN_INT_MASK) | TSEN_INT_MASK; + HWREG32(thermal->regs + REG_TSEN_PCTRL) = + HWREG32(thermal->regs + REG_TSEN_PCTRL) | BIT_HW_AUTO_MODE; +} + +static void enable_sensor_irq(struct k1x_thermal_sensor *sensor) +{ + rt_uint32_t temp; + struct k1x_thermal_sensor_desc *desc = sensor->desc; + + /* Clear the interrupt */ + temp = HWREG32(sensor->regs + desc->int_clr); + temp |= desc->bit_msk; + HWREG32(sensor->regs + desc->int_clr) = temp; + + /* Enable the interrupt */ + temp = HWREG32(sensor->regs + desc->int_msk); + temp &= ~desc->bit_msk; + HWREG32(sensor->regs + desc->int_msk) = temp; +} + +static void k1x_thermal_free(struct k1x_thermal *thermal) +{ + if (thermal->regs) + { + rt_iounmap(thermal->regs); + } + + if (!rt_is_err_or_null(thermal->clk)) + { + rt_clk_disable_unprepare(thermal->clk); + rt_clk_put(thermal->clk); + } + + if (!rt_is_err_or_null(thermal->rstc)) + { + rt_reset_control_assert(thermal->rstc); + rt_reset_control_put(thermal->rstc); + } + + if (thermal->sensors) + { + rt_free(thermal->sensors); + } + + rt_free(thermal); +} + +static rt_err_t k1x_thermal_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct k1x_thermal *thermal; + struct k1x_thermal_sensor_desc *desc = (void *)pdev->id->data; + + if (!desc) + { + return -RT_EINVAL; + } + + if (!(thermal = rt_calloc(1, sizeof(*thermal)))) + { + return -RT_ENOMEM; + } + + thermal->regs = rt_dm_dev_iomap(dev, 0); + if (!thermal->regs) + { + err = -RT_EINVAL; + goto _fail; + } + + thermal->irq = rt_dm_dev_get_irq(dev, 0); + if (thermal->irq < 0) + { + err = thermal->irq; + goto _fail; + } + + thermal->rstc = rt_reset_control_get_by_index(dev, 0); + if (rt_is_err(thermal->rstc)) + { + err = rt_ptr_err(thermal->rstc); + goto _fail; + } + + rt_reset_control_deassert(thermal->rstc); + + thermal->clk = rt_clk_get_by_index(dev, 0); + if (rt_is_err(thermal->clk)) + { + err = rt_ptr_err(thermal->clk); + goto _fail; + } + + rt_clk_prepare_enable(thermal->clk); + + /* Initialize the sensors */ + if ((err = init_sensors(dev, thermal, desc))) + { + goto _fail; + } + + thermal->sensors = rt_calloc(thermal->sr[1] - thermal->sr[0] + 1, sizeof(*thermal->sensors)); + if (!thermal->sensors) + { + err = -RT_ENOMEM; + goto _fail; + } + + /* Then register the thermal zone */ + for (int i = thermal->sr[0]; i <= thermal->sr[1]; ++i) + { + struct k1x_thermal_sensor *sensor; + struct rt_thermal_zone_device *tz; + + sensor = &thermal->sensors[i - thermal->sr[0]]; + sensor->regs = thermal->regs; + sensor->desc = &desc[i]; + + tz = &sensor->parent; + tz->ops = &k1x_thermal_ops; + tz->parent.ofw_node = dev->ofw_node; + + rt_dm_dev_set_name(&tz->parent, "tk1x-tz-%d", i); + rt_thermal_zone_device_register(tz); + + rt_hw_interrupt_install(thermal->irq, k1x_thermal_isr, sensor, + rt_dm_dev_get_name(&tz->parent)); + + /* Enable sensor low & higth threshold interrupt */ + enable_sensor_irq(sensor); + } + + /* Enable the sensor interrupt & using auto mode */ + enable_sensors(thermal); + + rt_hw_interrupt_umask(thermal->irq); + + dev->user_data = thermal; + + return RT_EOK; + +_fail: + k1x_thermal_free(thermal); + + return err; +} + +static rt_err_t k1x_thermal_remove(struct rt_platform_device *pdev) +{ + struct k1x_thermal *thermal = pdev->parent.user_data; + + rt_hw_interrupt_mask(thermal->irq); + + for (int i = thermal->sr[0]; i <= thermal->sr[1]; ++i) + { + struct k1x_thermal_sensor *sensor; + + sensor = &thermal->sensors[i - thermal->sr[0]]; + + rt_pic_detach_irq(thermal->irq, sensor); + rt_thermal_zone_device_unregister(&sensor->parent); + } + + k1x_thermal_free(thermal); + + return RT_EOK; +} + +static struct k1x_thermal_sensor_desc gsdesc[] = +{ + /* bjt0: local, sensor internal temperature */ + [0] = + { + .int_msk = 0x14, .int_clr = 0x10, .int_sta = 0x18, .offset = 0x0, .bit_msk = 0x6, + .se = { .bjt_en = 0x8, .en_val = 0x1, .offset = 0x0, .bit_msk = 0x1, }, + .sd = { .data_reg = 0x20, .offset = 0x0, .bit_msk = 0xffff, }, + .sr = { .temp_thrsh = 0x40, .low_offset = 0x0, .high_offset = 16, }, + }, + + /* bjt1: top */ + [1] = + { + .int_msk = 0x14, .int_clr = 0x10, .int_sta = 0x18, .offset = 0x3, .bit_msk = 0x18, + .se = { .bjt_en = 0x8, .en_val = 0x1, .offset = 0x1, .bit_msk = 0x2, }, + .sd = { .data_reg = 0x20, .offset = 16, .bit_msk = 0xffff0000, }, + .sr = { .temp_thrsh = 0x44, .low_offset = 0x0, .high_offset = 16, }, + }, + + /* bjt2: gpu */ + [2] = + { + .int_msk = 0x14, .int_clr = 0x10, .int_sta = 0x18, .offset = 0x5, .bit_msk = 0x60, + .se = { .bjt_en = 0x8, .en_val = 0x1, .offset = 0x2, .bit_msk = 0x4, }, + .sd = { .data_reg = 0x24, .offset = 0, .bit_msk = 0xffff, }, + .sr = { .temp_thrsh = 0x48, .low_offset = 0x0, .high_offset = 16, }, + }, + + /* bjt3: cluster0 */ + [3] = + { + .int_msk = 0x14, .int_clr = 0x10, .int_sta = 0x18, .offset = 0x7, .bit_msk = 0x180, + .se = { .bjt_en = 0x8, .en_val = 0x1, .offset = 0x3, .bit_msk = 0x8, }, + .sd = { .data_reg = 0x24, .offset = 16, .bit_msk = 0xffff0000, }, + .sr = { .temp_thrsh = 0x4c, .low_offset = 0x0, .high_offset = 16, }, + }, + + /* bjt4: cluster1 */ + [4] = + { + .int_msk = 0x14, .int_clr = 0x10, .int_sta = 0x18, .offset = 0x9, .bit_msk = 0x600, + .se = { .bjt_en = 0x8, .en_val = 0x1, .offset = 0x4, .bit_msk = 0x10, }, + .sd = { .data_reg = 0x28, .offset = 0, .bit_msk = 0xffff, }, + .sr = { .temp_thrsh = 0x50, .low_offset = 0x0, .high_offset = 16, }, + }, +}; + +static const struct rt_ofw_node_id k1x_thermal_ofw_ids[] = +{ + { .compatible = "spacemit,k1x-tsensor", .data = gsdesc, }, + { /* sentinel */ } +}; + +static struct rt_platform_driver k1x_thermal_driver = +{ + .name = "k1x-thermal", + .ids = k1x_thermal_ofw_ids, + + .probe = k1x_thermal_probe, + .remove = k1x_thermal_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(k1x_thermal_driver); diff --git a/bsp/spacemit/dm/watchdog/Kconfig b/bsp/spacemit/dm/watchdog/Kconfig new file mode 100644 index 000000000000..e84991358e42 --- /dev/null +++ b/bsp/spacemit/dm/watchdog/Kconfig @@ -0,0 +1,3 @@ +config RT_WDT_SPACEMIT_WATCHDOG + bool "Spacemit-k1x SoC Watchdog" + default n diff --git a/bsp/spacemit/dm/watchdog/SConscript b/bsp/spacemit/dm/watchdog/SConscript new file mode 100644 index 000000000000..5b3ece5b2e24 --- /dev/null +++ b/bsp/spacemit/dm/watchdog/SConscript @@ -0,0 +1,13 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_WDT_SPACEMIT_WATCHDOG']): + src += ['watchdog-k1x.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/dm/watchdog/watchdog-k1x.c b/bsp/spacemit/dm/watchdog/watchdog-k1x.c new file mode 100644 index 000000000000..a0a7b519d2ed --- /dev/null +++ b/bsp/spacemit/dm/watchdog/watchdog-k1x.c @@ -0,0 +1,470 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include + +#define DBG_TAG "wdt.k1x" +#define DBG_LVL DBG_INFO +#include + +/* Watchdog Timer Registers Offset */ +#define WDT_WMER 0x00b8 +#define WDT_WMR 0x00bc +#define WDT_WVR 0x00cc +#define WDT_WCR 0x00c8 +#define WDT_WSR 0x00c0 +#define WDT_WFAR 0x00b0 +#define WDT_WSAR 0x00b4 +#define WDT_WICR 0x00c4 + +/* Default timeout is 60s */ +#define SPACEMIT_WATCHDOG_MAX_TIMEOUT 255 +#define SPACEMIT_WATCHDOG_EXPIRE_TIME 100 +/* Touch watchdog every 30s */ +#define SPACEMIT_WATCHDOG_FEED_TIMEOUT 30 + +#define MPMU_APRR 0x1020 +#define MPMU_APRR_WDTR RT_BIT(4) +#define DEFAULT_SHIFT 8 +/* + * MPMU_APSR is a dummy reg which is used to handle reboot + * cmds. Its layout is: + * bit0~7: untouchable + * bit8~11: set to 0x1 when normal boot with no parameter + * set to 0x5 for other valid cmds. + */ +#define MPMU_ARSR 0x1028 +#define MPMU_ARSR_REBOOT_CMD(x) ((x) << 8) +#define MPMU_ARSR_SWR_MASK (0xf << 8) +#define REBOOT_CMD_NORMAL 0x1 +#define REBOOT_CMD_VALID 0x5 + +struct spa_wdt +{ + rt_watchdog_t parent; + + void *wdt_base; + void *mpmu_base; + + struct rt_clk *clk; + struct rt_reset_control *rstc; + + rt_uint32_t timeout; + + rt_bool_t ctrl; + rt_bool_t wdt_clk_open; + rt_bool_t enable_restart_handler; + + struct rt_spinlock wdt_lock; +}; + +#define raw_to_spa_wdt(raw) rt_container_of(raw, struct spa_wdt, parent) + +rt_inline rt_uint32_t spa_wdt_read(struct spa_wdt *swdt, unsigned reg) +{ + return HWREG32(swdt->wdt_base + reg); +} + +rt_inline void spa_wdt_write_access(struct spa_wdt *swdt) +{ + HWREG32(swdt->wdt_base + WDT_WFAR) = 0xbaba; + HWREG32(swdt->wdt_base + WDT_WSAR) = 0xeb10; +} + +rt_inline void spa_wdt_write(struct spa_wdt *swdt, unsigned reg, rt_uint32_t val) +{ + spa_wdt_write_access(swdt); + HWREG32(swdt->wdt_base + reg) = val; +} + +static rt_err_t spa_wdt_set_timeout(struct spa_wdt *swdt, unsigned timeout) +{ + /* + * the wdt timer is 16 bit, + * frequence is 256HZ + */ + unsigned int tick = timeout << DEFAULT_SHIFT; + + if ((long long)tick > 0xffff) + { + timeout = SPACEMIT_WATCHDOG_MAX_TIMEOUT; + tick = timeout << DEFAULT_SHIFT; + } + + spa_wdt_write(swdt, WDT_WMR, tick); + + swdt->timeout = timeout; + + return RT_EOK; +} + +static void spa_enable_wdt_clk(struct spa_wdt *swdt) +{ + rt_spin_lock(&swdt->wdt_lock); + + if (!swdt->wdt_clk_open) + { + rt_clk_prepare_enable(swdt->clk); + rt_reset_control_deassert(swdt->rstc); + swdt->wdt_clk_open = RT_TRUE; + } + + rt_spin_unlock(&swdt->wdt_lock); +} + +static void spa_disable_wdt_clk(struct spa_wdt *swdt) +{ + rt_spin_lock(&swdt->wdt_lock); + + if (swdt->wdt_clk_open) + { + rt_clk_disable_unprepare(swdt->clk); + rt_reset_control_assert(swdt->rstc); + swdt->wdt_clk_open = RT_FALSE; + } + + rt_spin_unlock(&swdt->wdt_lock); +} + +static rt_err_t spa_wdt_stop(struct spa_wdt *swdt) +{ + rt_spin_lock(&swdt->wdt_lock); + + /* Reset counter */ + spa_wdt_write(swdt, WDT_WCR, 0x1); + + /* Disable WDT */ + spa_wdt_write(swdt, WDT_WMER, 0x0); + + swdt->ctrl = RT_FALSE; + + rt_spin_unlock(&swdt->wdt_lock); + + rt_thread_mdelay(3); + + spa_disable_wdt_clk(swdt); + + return RT_EOK; +} + +static rt_err_t spa_wdt_start(struct spa_wdt *swdt) +{ + void *mpmu_aprr; + rt_uint32_t reg; + + spa_enable_wdt_clk(swdt); + + rt_spin_lock(&swdt->wdt_lock); + + /* Set timeout = 100s */ + spa_wdt_set_timeout(swdt, SPACEMIT_WATCHDOG_EXPIRE_TIME); + + /* Enable counter and rstc/interrupt */ + spa_wdt_write(swdt, WDT_WMER, 0x3); + + /* Negate hardware rstc to the WDT after system rstc */ + mpmu_aprr = swdt->mpmu_base + MPMU_APRR; + reg = HWREG32(mpmu_aprr); + reg |= MPMU_APRR_WDTR; + HWREG32(mpmu_aprr) = reg; + + /* Clear previous WDT status */ + spa_wdt_write(swdt, WDT_WSR, 0x0); + + swdt->ctrl = RT_TRUE; + + rt_spin_unlock(&swdt->wdt_lock); + + return RT_EOK; +} + +static rt_err_t spa_wdt_ping(struct spa_wdt *swdt) +{ + rt_spin_lock(&swdt->wdt_lock); + + spa_wdt_write(swdt, WDT_WCR, 0x1); + + rt_spin_unlock(&swdt->wdt_lock); + + return RT_EOK; +} + +static rt_err_t spa_wdt_init(rt_watchdog_t *wdt) +{ + return RT_EOK; +} + +static rt_err_t spa_wdt_control(rt_watchdog_t *wdt, int cmd, void *args) +{ + rt_err_t err = RT_EOK; + struct spa_wdt *swdt = raw_to_spa_wdt(wdt); + + switch (cmd) + { + case RT_DEVICE_CTRL_WDT_GET_TIMEOUT: + *(rt_uint32_t *)args = swdt->timeout; + break; + + case RT_DEVICE_CTRL_WDT_SET_TIMEOUT: + spa_wdt_set_timeout(swdt, *(rt_uint32_t *)args); + break; + + case RT_DEVICE_CTRL_WDT_GET_TIMELEFT: + err = -RT_ENOSYS; + break; + + case RT_DEVICE_CTRL_WDT_KEEPALIVE: + spa_wdt_ping(swdt); + break; + + case RT_DEVICE_CTRL_WDT_START: + spa_wdt_start(swdt); + break; + + case RT_DEVICE_CTRL_WDT_STOP: + spa_wdt_stop(swdt); + break; + + default: + err = -RT_EINVAL; + } + + return err; +} + +static const struct rt_watchdog_ops spa_wdt_ops = +{ + .init = spa_wdt_init, + .control = spa_wdt_control, +}; + +static rt_err_t spa_wdt_restart_handler(struct rt_device *dev, char *cmd) +{ + rt_uint32_t reg; + void *mpmu_arsr, *mpmu_aprr; + rt_watchdog_t *wdt = rt_container_of(dev, rt_watchdog_t, parent); + struct spa_wdt *swdt = raw_to_spa_wdt(wdt); + + rt_hw_spin_lock(&swdt->wdt_lock.lock); + + mpmu_arsr = swdt->mpmu_base + MPMU_ARSR; + reg = HWREG32(mpmu_arsr); + reg &= ~MPMU_ARSR_SWR_MASK; + + if (!cmd) + { + reg |= MPMU_ARSR_REBOOT_CMD(REBOOT_CMD_NORMAL); + } + else + { + reg |= MPMU_ARSR_REBOOT_CMD(REBOOT_CMD_VALID); + } + + HWREG32(mpmu_arsr) = reg; + + spa_enable_wdt_clk(swdt); + + spa_wdt_write(swdt, WDT_WSR, 0x0); + spa_wdt_write(swdt, WDT_WMR, 0x1); + spa_wdt_write(swdt, WDT_WMER, 0x3); + spa_wdt_write(swdt, WDT_WCR, 0x1); + + mpmu_aprr = swdt->mpmu_base + MPMU_APRR; + reg = HWREG32(mpmu_aprr); + reg |= MPMU_APRR_WDTR; + HWREG32(mpmu_aprr) = reg; + + rt_thread_mdelay(5000); + + rt_hw_spin_unlock(&swdt->wdt_lock.lock); + + return RT_EOK; +} + +#ifdef RT_USING_PM +static rt_err_t spa_wdt_pm_suspend(const struct rt_device *device, rt_uint8_t mode) +{ + rt_watchdog_t *wdt = rt_container_of(device, rt_watchdog_t, parent); + struct spa_wdt *swdt = raw_to_spa_wdt(wdt); + + if (swdt->ctrl) + { + spa_wdt_stop(swdt); + } + + return RT_EOK; +} + +static void spa_wdt_pm_resume(const struct rt_device *device, rt_uint8_t mode) +{ + rt_watchdog_t *wdt = rt_container_of(device, rt_watchdog_t, parent); + struct spa_wdt *swdt = raw_to_spa_wdt(wdt); + + if (swdt->ctrl) + { + spa_wdt_start(swdt); + } +} + +static const struct rt_device_pm_ops spa_wdt_pm_ops = +{ + .suspend = spa_wdt_pm_suspend, + .resume = spa_wdt_pm_resume, +}; +#endif /* RT_USING_PM */ + +static void spa_wdt_free(struct spa_wdt *swdt) +{ + if (swdt->ctrl) + { + spa_wdt_stop(swdt); + } + + spa_disable_wdt_clk(swdt); + + if (!rt_is_err_or_null(swdt->clk)) + { + rt_clk_put(swdt->clk); + } + + if (!rt_is_err_or_null(swdt->rstc)) + { + rt_reset_control_put(swdt->rstc); + } +} + +static rt_err_t spa_wdt_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + void *mpmu_arsr; + const char *dev_name; + struct rt_device *dev = &pdev->parent; + struct spa_wdt *swdt = rt_calloc(1, sizeof(*swdt)); + + if (!swdt) + { + return -RT_ENOMEM; + } + + if (!(swdt->wdt_base = rt_dm_dev_iomap(dev, 0))) + { + err = -RT_EIO; + goto _fail; + } + + if (!(swdt->mpmu_base = rt_dm_dev_iomap(dev, 1))) + { + err = -RT_EIO; + goto _fail; + } + + mpmu_arsr = swdt->mpmu_base + MPMU_ARSR; + HWREG32(mpmu_arsr) = HWREG32(mpmu_arsr) & ~MPMU_ARSR_SWR_MASK; + + swdt->clk = rt_clk_get_by_index(dev, 0); + if (rt_is_err(swdt->clk)) + { + err = rt_ptr_err(swdt->clk); + goto _fail; + } + + swdt->rstc = rt_reset_control_get_by_index(dev, 0); + if (rt_is_err(swdt->rstc)) + { + err = rt_ptr_err(swdt->rstc); + goto _fail; + } + + swdt->enable_restart_handler = rt_dm_dev_prop_read_bool(dev, "spa,wdt-enable-restart-handler"); + + /* + * The writing of some WDT registers must be + * under the condition of that WDT clock is on + */ + spa_enable_wdt_clk(swdt); + + rt_spin_lock_init(&swdt->wdt_lock); + + dev->user_data = swdt; + + swdt->parent.ops = &spa_wdt_ops; + + rt_dm_dev_set_name_auto(&swdt->parent.parent, "wdt"); + dev_name = rt_dm_dev_get_name(&swdt->parent.parent); + + if ((err = rt_hw_watchdog_register(&swdt->parent, dev_name, 0, swdt))) + { + goto _fail; + } + +#ifdef RT_USING_PM + rt_pm_device_register(&swdt->parent.parent, &spa_wdt_pm_ops); +#endif + + if (swdt->enable_restart_handler) + { + rt_dm_reboot_mode_register(&swdt->parent.parent, spa_wdt_restart_handler); + } + + return RT_EOK; + +_fail: + spa_wdt_free(swdt); + + return err; +} + +static rt_err_t spa_wdt_remove(struct rt_platform_device *pdev) +{ + struct spa_wdt *swdt = pdev->parent.user_data; + +#ifdef RT_USING_PM + rt_pm_device_unregister(&swdt->parent.parent); +#endif + + rt_device_unregister(&swdt->parent.parent); + + spa_wdt_free(swdt); + + return RT_EOK; +} + +static rt_err_t spa_wdt_shutdown(struct rt_platform_device *pdev) +{ + struct spa_wdt *swdt = pdev->parent.user_data; + + spa_wdt_stop(swdt); + + /* No need to disable clk if enable restart_handler */ + if (swdt->enable_restart_handler) + { + spa_enable_wdt_clk(swdt); + } + + return RT_EOK; +} + +static const struct rt_ofw_node_id spa_wdt_ofw_ids[] = +{ + { .compatible = "spacemit,soc-wdt" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver spa_wdt_driver = +{ + .name = "spa-wdt", + .ids = spa_wdt_ofw_ids, + + .probe = spa_wdt_probe, + .remove = spa_wdt_remove, + .shutdown = spa_wdt_shutdown, +}; +RT_PLATFORM_DRIVER_EXPORT(spa_wdt_driver); diff --git a/bsp/spacemit/k1/.config b/bsp/spacemit/k1/.config new file mode 100644 index 000000000000..7ea65bc39455 --- /dev/null +++ b/bsp/spacemit/k1/.config @@ -0,0 +1,1927 @@ + +# +# RT-Thread Kernel +# + +# +# klibc options +# + +# +# rt_vsnprintf options +# +# CONFIG_RT_KLIBC_USING_LIBC_VSNPRINTF is not set +# CONFIG_RT_KLIBC_USING_VSNPRINTF_LONGLONG is not set +# CONFIG_RT_KLIBC_USING_VSNPRINTF_STANDARD is not set +# end of rt_vsnprintf options + +# +# rt_vsscanf options +# +# CONFIG_RT_KLIBC_USING_LIBC_VSSCANF is not set +# end of rt_vsscanf options + +# +# rt_memset options +# +# CONFIG_RT_KLIBC_USING_USER_MEMSET is not set +# CONFIG_RT_KLIBC_USING_LIBC_MEMSET is not set +# CONFIG_RT_KLIBC_USING_TINY_MEMSET is not set +# end of rt_memset options + +# +# rt_memcpy options +# +# CONFIG_RT_KLIBC_USING_USER_MEMCPY is not set +# CONFIG_RT_KLIBC_USING_LIBC_MEMCPY is not set +# CONFIG_RT_KLIBC_USING_TINY_MEMCPY is not set +# end of rt_memcpy options + +# +# rt_memmove options +# +# CONFIG_RT_KLIBC_USING_USER_MEMMOVE is not set +# CONFIG_RT_KLIBC_USING_LIBC_MEMMOVE is not set +# end of rt_memmove options + +# +# rt_memcmp options +# +# CONFIG_RT_KLIBC_USING_USER_MEMCMP is not set +# CONFIG_RT_KLIBC_USING_LIBC_MEMCMP is not set +# end of rt_memcmp options + +# +# rt_strstr options +# +# CONFIG_RT_KLIBC_USING_USER_STRSTR is not set +# CONFIG_RT_KLIBC_USING_LIBC_STRSTR is not set +# end of rt_strstr options + +# +# rt_strcasecmp options +# +# CONFIG_RT_KLIBC_USING_USER_STRCASECMP is not set +# end of rt_strcasecmp options + +# +# rt_strncpy options +# +# CONFIG_RT_KLIBC_USING_USER_STRNCPY is not set +# CONFIG_RT_KLIBC_USING_LIBC_STRNCPY is not set +# end of rt_strncpy options + +# +# rt_strcpy options +# +# CONFIG_RT_KLIBC_USING_USER_STRCPY is not set +# CONFIG_RT_KLIBC_USING_LIBC_STRCPY is not set +# end of rt_strcpy options + +# +# rt_strncmp options +# +# CONFIG_RT_KLIBC_USING_USER_STRNCMP is not set +# CONFIG_RT_KLIBC_USING_LIBC_STRNCMP is not set +# end of rt_strncmp options + +# +# rt_strcmp options +# +# CONFIG_RT_KLIBC_USING_USER_STRCMP is not set +# CONFIG_RT_KLIBC_USING_LIBC_STRCMP is not set +# end of rt_strcmp options + +# +# rt_strlen options +# +# CONFIG_RT_KLIBC_USING_USER_STRLEN is not set +# CONFIG_RT_KLIBC_USING_LIBC_STRLEN is not set +# end of rt_strlen options + +# +# rt_strnlen options +# +# CONFIG_RT_KLIBC_USING_USER_STRNLEN is not set +# end of rt_strnlen options +# end of klibc options + +CONFIG_RT_NAME_MAX=24 +# CONFIG_RT_USING_ARCH_DATA_TYPE is not set +# CONFIG_RT_USING_NANO is not set +# CONFIG_RT_USING_SMART is not set +# CONFIG_RT_USING_AMP is not set +CONFIG_RT_USING_SMP=y +CONFIG_RT_CPUS_NR=4 +CONFIG_RT_ALIGN_SIZE=8 +# CONFIG_RT_THREAD_PRIORITY_8 is not set +CONFIG_RT_THREAD_PRIORITY_32=y +# CONFIG_RT_THREAD_PRIORITY_256 is not set +CONFIG_RT_THREAD_PRIORITY_MAX=32 +CONFIG_RT_TICK_PER_SECOND=100 +CONFIG_RT_USING_OVERFLOW_CHECK=y +CONFIG_RT_USING_HOOK=y +CONFIG_RT_HOOK_USING_FUNC_PTR=y +# CONFIG_RT_USING_HOOKLIST is not set +CONFIG_RT_USING_IDLE_HOOK=y +CONFIG_RT_IDLE_HOOK_LIST_SIZE=4 +CONFIG_IDLE_THREAD_STACK_SIZE=16384 +CONFIG_SYSTEM_THREAD_STACK_SIZE=16384 +CONFIG_RT_USING_TIMER_SOFT=y +CONFIG_RT_TIMER_THREAD_PRIO=4 +CONFIG_RT_TIMER_THREAD_STACK_SIZE=16384 +# CONFIG_RT_USING_TIMER_ALL_SOFT is not set +CONFIG_RT_USING_CPU_USAGE_TRACER=y +CONFIG_RT_CPU_USAGE_CALC_INTERVAL_MS=200 + +# +# kservice options +# +# CONFIG_RT_USING_TINY_FFS is not set +# end of kservice options + +CONFIG_RT_USING_DEBUG=y +CONFIG_RT_DEBUGING_ASSERT=y +CONFIG_RT_DEBUGING_COLOR=y +CONFIG_RT_DEBUGING_CONTEXT=y +# CONFIG_RT_DEBUGING_AUTO_INIT is not set +# CONFIG_RT_DEBUGING_SPINLOCK is not set +# CONFIG_RT_DEBUGING_CRITICAL is not set +# CONFIG_RT_USING_CI_ACTION is not set + +# +# Inter-Thread communication +# +CONFIG_RT_USING_SEMAPHORE=y +CONFIG_RT_USING_MUTEX=y +CONFIG_RT_USING_EVENT=y +CONFIG_RT_USING_MAILBOX=y +CONFIG_RT_USING_MESSAGEQUEUE=y +# CONFIG_RT_USING_MESSAGEQUEUE_PRIORITY is not set +CONFIG_RT_USING_SIGNALS=y +# end of Inter-Thread communication + +# +# Memory Management +# +CONFIG_RT_USING_MEMPOOL=y +# CONFIG_RT_USING_SMALL_MEM is not set +CONFIG_RT_USING_SLAB=y +CONFIG_RT_USING_MEMHEAP=y +CONFIG_RT_MEMHEAP_FAST_MODE=y +# CONFIG_RT_MEMHEAP_BEST_MODE is not set +# CONFIG_RT_USING_SMALL_MEM_AS_HEAP is not set +# CONFIG_RT_USING_MEMHEAP_AS_HEAP is not set +CONFIG_RT_USING_SLAB_AS_HEAP=y +# CONFIG_RT_USING_USERHEAP is not set +# CONFIG_RT_USING_NOHEAP is not set +CONFIG_RT_USING_MEMTRACE=y +# CONFIG_RT_USING_HEAP_ISR is not set +CONFIG_RT_USING_HEAP=y +# end of Memory Management + +CONFIG_RT_USING_DEVICE=y +CONFIG_RT_USING_DEVICE_OPS=y +CONFIG_RT_USING_INTERRUPT_INFO=y +# CONFIG_RT_USING_THREADSAFE_PRINTF is not set +CONFIG_RT_USING_CONSOLE=y +CONFIG_RT_CONSOLEBUF_SIZE=256 +CONFIG_RT_CONSOLE_DEVICE_NAME="uart0" +CONFIG_RT_USING_CONSOLE_OUTPUT_CTL=y +CONFIG_RT_VER_NUM=0x50300 +CONFIG_RT_USING_STDC_ATOMIC=y +CONFIG_RT_BACKTRACE_LEVEL_MAX_NR=32 +# end of RT-Thread Kernel + +CONFIG_ARCH_TEXT_OFFSET=0x200000 +CONFIG_ARCH_RAM_OFFSET=0 +CONFIG_ARCH_SECONDARY_CPU_STACK_SIZE=4096 +CONFIG_ARCH_HEAP_SIZE=0x4000000 +CONFIG_ARCH_INIT_PAGE_SIZE=0x200000 +CONFIG_ARCH_CPU_64BIT=y +CONFIG_RT_USING_CACHE=y +CONFIG_RT_USING_HW_ATOMIC=y +CONFIG_RT_USING_CPU_FFS=y +CONFIG_ARCH_MM_MMU=y +CONFIG_ARCH_RISCV=y +CONFIG_ARCH_RISCV_FPU=y +CONFIG_ARCH_RISCV_FPU_D=y +CONFIG_ARCH_RISCV64=y + +# +# RISC-V Architecture Configuration +# +CONFIG_RT_USING_RISCV_NEW_COMMON=y +# CONFIG_ARCH_RISCV_USING_IRQ_STACK is not set +# CONFIG_RT_USING_USERSPACE_32BIT_LIMIT is not set +# end of RISC-V Architecture Configuration + +CONFIG_ARCH_USING_NEW_CTX_SWITCH=y + +# +# RT-Thread Components +# +CONFIG_RT_USING_COMPONENTS_INIT=y +CONFIG_RT_USING_USER_MAIN=y +CONFIG_RT_MAIN_THREAD_STACK_SIZE=16384 +CONFIG_RT_MAIN_THREAD_PRIORITY=10 +# CONFIG_RT_USING_LEGACY is not set +CONFIG_RT_USING_MSH=y +CONFIG_RT_USING_FINSH=y +CONFIG_FINSH_USING_MSH=y +CONFIG_FINSH_THREAD_NAME="tshell" +CONFIG_FINSH_THREAD_PRIORITY=20 +CONFIG_FINSH_THREAD_STACK_SIZE=16384 +CONFIG_FINSH_USING_HISTORY=y +CONFIG_FINSH_HISTORY_LINES=10 +# CONFIG_FINSH_USING_WORD_OPERATION is not set +# CONFIG_FINSH_USING_FUNC_EXT is not set +CONFIG_FINSH_USING_SYMTAB=y +CONFIG_FINSH_CMD_SIZE=80 +CONFIG_MSH_USING_BUILT_IN_COMMANDS=y +CONFIG_FINSH_USING_DESCRIPTION=y +# CONFIG_FINSH_ECHO_DISABLE_DEFAULT is not set +# CONFIG_FINSH_USING_AUTH is not set +CONFIG_FINSH_ARG_MAX=10 +CONFIG_FINSH_USING_OPTION_COMPLETION=y + +# +# DFS: device virtual file system +# +CONFIG_RT_USING_DFS=y +CONFIG_DFS_USING_POSIX=y +CONFIG_DFS_USING_WORKDIR=y +CONFIG_DFS_FD_MAX=32 +# CONFIG_RT_USING_DFS_V1 is not set +CONFIG_RT_USING_DFS_V2=y +CONFIG_RT_USING_DFS_ELMFAT=y + +# +# elm-chan's FatFs, Generic FAT Filesystem Module +# +CONFIG_RT_DFS_ELM_CODE_PAGE=437 +CONFIG_RT_DFS_ELM_WORD_ACCESS=y +# CONFIG_RT_DFS_ELM_USE_LFN_0 is not set +# CONFIG_RT_DFS_ELM_USE_LFN_1 is not set +# CONFIG_RT_DFS_ELM_USE_LFN_2 is not set +CONFIG_RT_DFS_ELM_USE_LFN_3=y +CONFIG_RT_DFS_ELM_USE_LFN=3 +CONFIG_RT_DFS_ELM_LFN_UNICODE_0=y +# CONFIG_RT_DFS_ELM_LFN_UNICODE_1 is not set +# CONFIG_RT_DFS_ELM_LFN_UNICODE_2 is not set +# CONFIG_RT_DFS_ELM_LFN_UNICODE_3 is not set +CONFIG_RT_DFS_ELM_LFN_UNICODE=0 +CONFIG_RT_DFS_ELM_MAX_LFN=255 +CONFIG_RT_DFS_ELM_DRIVES=2 +CONFIG_RT_DFS_ELM_MAX_SECTOR_SIZE=512 +# CONFIG_RT_DFS_ELM_USE_ERASE is not set +CONFIG_RT_DFS_ELM_REENTRANT=y +CONFIG_RT_DFS_ELM_MUTEX_TIMEOUT=3000 +CONFIG_RT_DFS_ELM_USE_EXFAT=y +# end of elm-chan's FatFs, Generic FAT Filesystem Module + +CONFIG_RT_USING_DFS_DEVFS=y +CONFIG_RT_USING_DFS_ROMFS=y +# CONFIG_RT_USING_DFS_CROMFS is not set +# CONFIG_RT_USING_DFS_TMPFS is not set +# CONFIG_RT_USING_DFS_MQUEUE is not set +# end of DFS: device virtual file system + +# CONFIG_RT_USING_FAL is not set + +# +# Device Drivers +# +CONFIG_RT_USING_DM=y +# CONFIG_RT_USING_DEV_BUS is not set +CONFIG_RT_USING_DEVICE_IPC=y +CONFIG_RT_UNAMED_PIPE_NUMBER=64 +CONFIG_RT_USING_SYSTEM_WORKQUEUE=y +CONFIG_RT_SYSTEM_WORKQUEUE_STACKSIZE=8192 +CONFIG_RT_SYSTEM_WORKQUEUE_PRIORITY=23 +CONFIG_RT_USING_SERIAL=y +CONFIG_RT_USING_SERIAL_V1=y +# CONFIG_RT_USING_SERIAL_V2 is not set +CONFIG_RT_SERIAL_USING_DMA=y +CONFIG_RT_SERIAL_RB_BUFSZ=64 +CONFIG_RT_USING_SERIAL_BYPASS=y +# CONFIG_RT_SERIAL_EARLY_HVC is not set +# CONFIG_RT_SERIAL_PL011 is not set +CONFIG_RT_SERIAL_8250=y +# CONFIG_RT_SERIAL_8250_DW is not set +# CONFIG_RT_SERIAL_8250_PCI is not set +CONFIG_RT_SERIAL_PXA=y +CONFIG_RT_SERIAL_EARLY_SBI=y +# CONFIG_RT_USING_CAN is not set +CONFIG_RT_USING_ADC=y +# CONFIG_RT_USING_ADC_V2 is not set +CONFIG_RT_USING_ADC_V1=y +CONFIG_RT_ADC_SPACEMIT_PMIC=y +CONFIG_RT_USING_CLOCK_TIME=y +# CONFIG_RT_USING_CLOCK_TIMER_TRIGGER is not set +CONFIG_CLOCK_TIMER_FREQ=0 +CONFIG_RT_CLOCK_TIME_SPACEMIT_K1X=y +CONFIG_RT_USING_ETHERNET=y +# CONFIG_RT_ETHERNET_CADENCE is not set +# CONFIG_RT_ETHERNET_DWMAC is not set +CONFIG_RT_ETHERNET_K1X_EMAC=y +CONFIG_RT_ETHERNET_K1X_EMAC_PTP=y +CONFIG_RT_USING_I2C=y +# CONFIG_RT_I2C_DEBUG is not set +CONFIG_RT_USING_I2C_BITOPS=y +# CONFIG_RT_I2C_BITOPS_DEBUG is not set +# CONFIG_RT_USING_SOFT_I2C is not set +CONFIG_RT_I2C_SPACEMIT_K1X=y +# CONFIG_RT_USING_PHY is not set +CONFIG_RT_USING_PHY_V2=y +CONFIG_RT_PHY_V2_REALTEK=y +# CONFIG_RT_USING_DAC is not set +CONFIG_RT_USING_NULL=y +CONFIG_RT_USING_ZERO=y +CONFIG_RT_USING_RANDOM=y +CONFIG_RT_USING_PWM=y +CONFIG_RT_PWM_PXA=y +# CONFIG_RT_USING_PULSE_ENCODER is not set +# CONFIG_RT_USING_INPUT_CAPTURE is not set +CONFIG_RT_USING_MTD_NOR=y +# CONFIG_RT_USING_MTD_NOR_CFI is not set +CONFIG_RT_USING_MTD_NOR_SPI=y +# CONFIG_RT_USING_MTD_NAND is not set +# CONFIG_RT_USING_PM is not set +CONFIG_RT_USING_RTC=y +CONFIG_RT_USING_ALARM=y +CONFIG_RT_ALARM_STACK_SIZE=16384 +CONFIG_RT_ALARM_TIMESLICE=5 +CONFIG_RT_ALARM_PRIORITY=10 +# CONFIG_RT_ALARM_USING_LOCAL_TIME is not set +# CONFIG_RT_USING_SOFT_RTC is not set +# CONFIG_RT_RTC_DS1302 is not set +# CONFIG_RT_RTC_DS1307 is not set +# CONFIG_RT_RTC_GOLDFISH is not set +# CONFIG_RT_RTC_HYM8563 is not set +# CONFIG_RT_RTC_PCF8523 is not set +# CONFIG_RT_RTC_PCF8563 is not set +# CONFIG_RT_RTC_PL031 is not set +# CONFIG_RT_RTC_RX8010 is not set +CONFIG_RT_RTC_SPACEMIT_PMIC=y +CONFIG_RT_USING_SDIO=y +CONFIG_RT_SDIO_STACK_SIZE=16384 +CONFIG_RT_SDIO_THREAD_PRIORITY=15 +CONFIG_RT_MMCSD_STACK_SIZE=16384 +CONFIG_RT_MMCSD_THREAD_PRIORITY=22 +CONFIG_RT_MMCSD_MAX_PARTITION=16 +# CONFIG_RT_SDIO_DEBUG is not set +CONFIG_RT_USING_SDHCI=y +# CONFIG_RT_SDIO_SDHCI_PCI is not set +# CONFIG_RT_SDIO_DW_MMC is not set +# CONFIG_RT_SDIO_SDHCI_DWCMSHC is not set +CONFIG_RT_SDIO_SDHCI_SPACEMIT_K1X=y +CONFIG_RT_USING_SPI=y +# CONFIG_RT_USING_SPI_ISR is not set +# CONFIG_RT_USING_SPI_BITOPS is not set +# CONFIG_RT_USING_SOFT_SPI is not set +CONFIG_RT_USING_QSPI=y +# CONFIG_RT_USING_SPI_MSD is not set +CONFIG_RT_USING_SFUD=y +CONFIG_RT_SFUD_USING_SFDP=y +CONFIG_RT_SFUD_USING_FLASH_INFO_TABLE=y +CONFIG_RT_SFUD_USING_QSPI=y +CONFIG_RT_SFUD_SPI_MAX_HZ=50000000 +CONFIG_RT_DEBUG_SFUD=y +# CONFIG_RT_USING_ENC28J60 is not set +# CONFIG_RT_USING_SPI_WIFI is not set +CONFIG_RT_SPI_K1X_QSPI=y +CONFIG_RT_SPI_K1X=y +CONFIG_RT_USING_WDT=y +# CONFIG_RT_WDT_DW is not set +# CONFIG_RT_WDT_I6300ESB is not set +CONFIG_RT_WDT_SPACEMIT_WATCHDOG=y +CONFIG_RT_USING_AUDIO=y +CONFIG_RT_AUDIO_REPLAY_MP_BLOCK_SIZE=4096 +CONFIG_RT_AUDIO_REPLAY_MP_BLOCK_COUNT=4 +CONFIG_RT_AUDIO_RECORD_PIPE_SIZE=8192 +# CONFIG_RT_AUDIO_INTEL_HDA is not set +CONFIG_RT_AUDIO_SPACEMIT=y +CONFIG_RT_AUDIO_SPACEMIT_CODEC=y +CONFIG_RT_AUDIO_SPACEMIT_CODEC_ES8326=y +# CONFIG_RT_USING_SENSOR is not set +# CONFIG_RT_USING_TOUCH is not set +CONFIG_RT_USING_LCD=y +CONFIG_RT_USING_GRAPHIC=y +CONFIG_RT_GRAPHIC_BACKLIGHT=y +# CONFIG_RT_GRAPHIC_BACKLIGHT_GPIO is not set +CONFIG_RT_GRAPHIC_BACKLIGHT_PWM=y +CONFIG_RT_GRAPHIC_FB=y +# CONFIG_RT_GRAPHIC_FB_ILI9486 is not set +# CONFIG_RT_GRAPHIC_FB_SIMPLE is not set +CONFIG_RT_GRAPHIC_FB_SPACEMIT=y +CONFIG_RT_GRAPHIC_LOGO=y +# CONFIG_RT_GRAPHIC_LOGO_NONE is not set +# CONFIG_RT_GRAPHIC_LOGO_RT_THREAD_CLUT224 is not set +# CONFIG_RT_GRAPHIC_LOGO_RT_THREAD_WHITE_CLUT224 is not set +# CONFIG_RT_GRAPHIC_LOGO_BIANBU_CLUT224 is not set +CONFIG_RT_GRAPHIC_LOGO_SPACEMIT_CLUT224=y +CONFIG_RT_GRAPHIC_LOGO_SPACEMIT_CLUT224_PATH="../dm/graphic/logo/logo-spacemit-clut224.ppm" +CONFIG_RT_USING_HWCRYPTO=y +CONFIG_RT_HWCRYPTO_DEFAULT_NAME="hwcryto" +CONFIG_RT_HWCRYPTO_IV_MAX_SIZE=16 +CONFIG_RT_HWCRYPTO_KEYBIT_MAX_SIZE=256 +# CONFIG_RT_HWCRYPTO_USING_GCM is not set +CONFIG_RT_HWCRYPTO_USING_AES=y +CONFIG_RT_HWCRYPTO_USING_AES_ECB=y +CONFIG_RT_HWCRYPTO_USING_AES_CBC=y +# CONFIG_RT_HWCRYPTO_USING_AES_CFB is not set +# CONFIG_RT_HWCRYPTO_USING_AES_CTR is not set +# CONFIG_RT_HWCRYPTO_USING_AES_OFB is not set +# CONFIG_RT_HWCRYPTO_USING_DES is not set +# CONFIG_RT_HWCRYPTO_USING_3DES is not set +# CONFIG_RT_HWCRYPTO_USING_RC4 is not set +# CONFIG_RT_HWCRYPTO_USING_MD5 is not set +# CONFIG_RT_HWCRYPTO_USING_SHA1 is not set +# CONFIG_RT_HWCRYPTO_USING_SHA2 is not set +CONFIG_RT_HWCRYPTO_USING_RNG=y +# CONFIG_RT_HWCRYPTO_USING_CRC is not set +# CONFIG_RT_HWCRYPTO_USING_BIGNUM is not set +CONFIG_RT_HWCRYPTO_SPACEMIT=y +CONFIG_RT_HWCRYPTO_RNG_SPACEMIT=y +# CONFIG_RT_USING_WIFI is not set +CONFIG_RT_USING_PTP=y +CONFIG_RT_USING_LED=y +CONFIG_RT_LED_GPIO=y +# CONFIG_RT_LED_PWM is not set +# CONFIG_RT_LED_SYSCON is not set +CONFIG_RT_USING_INPUT=y +CONFIG_RT_INPUT_POWER=y +# CONFIG_RT_INPUT_UAPI is not set +# CONFIG_RT_INPUT_JOYSTICK is not set +# CONFIG_RT_INPUT_KEYBOARD is not set +CONFIG_RT_INPUT_MISC=y +# CONFIG_RT_INPUT_MISC_BUTTON_E3X0 is not set +CONFIG_RT_INPUT_MISC_PWRKEY_SPACEMIT_PMIC=y +# CONFIG_RT_INPUT_TOUCHSCREEN is not set +CONFIG_RT_USING_MBOX=y +# CONFIG_RT_MBOX_PIC is not set +CONFIG_RT_MBOX_K1X=y +# CONFIG_RT_USING_HWSPINLOCK is not set +CONFIG_RT_USING_RPMSG=y +CONFIG_RT_RPMSG_CHAR_MSG_MAX=64 +CONFIG_RT_RPMSG_CHAR_MSG_SIZE_MAX=256 +# CONFIG_RT_RPMSG_RT_THREAD_VIRTIO is not set +# CONFIG_RT_USING_PHYE is not set +CONFIG_RT_USING_ATA=y +CONFIG_RT_ATA_AHCI=y +CONFIG_RT_ATA_AHCI_PCI=y +CONFIG_RT_USING_NVME=y +CONFIG_RT_USING_NVME_IO_QUEUE=4 +CONFIG_RT_NVME_PCI=y +CONFIG_RT_USING_BLK=y + +# +# Partition Types +# +CONFIG_RT_BLK_PARTITION_DFS=y +CONFIG_RT_BLK_PARTITION_EFI=y +# end of Partition Types + +CONFIG_RT_USING_SCSI=y +CONFIG_RT_SCSI_SD=y +# CONFIG_RT_SCSI_CDROM is not set +# CONFIG_RT_USING_UFS is not set +# CONFIG_RT_USING_FIRMWARE is not set +# CONFIG_RT_USING_TEE is not set +# CONFIG_RT_USING_HWCACHE is not set +CONFIG_RT_USING_DVFS=y +CONFIG_RT_USING_DVFS_EVENT=y +CONFIG_RT_USING_DVFS_OPP_RETRY_MAX=10 + +# +# DVFS Event Drivers +# + +# +# DVFS CPUfreq Drivers +# +CONFIG_RT_DVFS_SPACEMIT_CPUFREQ=y + +# +# DVFS Devfreq Drivers +# +CONFIG_RT_USING_REGULATOR=y +# CONFIG_RT_REGULATOR_FAN53555 is not set +CONFIG_RT_REGULATOR_FIXED=y +CONFIG_RT_REGULATOR_GPIO=y +# CONFIG_RT_REGULATOR_PWM is not set +CONFIG_RT_REGULATOR_SPACEMIT_PMIC=y +CONFIG_RT_USING_RESET=y +# CONFIG_RT_RESET_SIMPLE is not set +CONFIG_RT_RESET_SPACEMIT_K1=y + +# +# Power Management (PM) Domains device drivers +# +CONFIG_RT_PMDOMAIN_K1X=y +# end of Power Management (PM) Domains device drivers + +CONFIG_RT_USING_POWER_RESET=y +# CONFIG_RT_POWER_RESET_GPIO_POWEROFF is not set +# CONFIG_RT_POWER_RESET_GPIO_RESTART is not set +# CONFIG_RT_POWER_RESET_SYSCON_POWEROFF is not set +# CONFIG_RT_POWER_RESET_SYSCON_REBOOT_MODE is not set +# CONFIG_RT_POWER_RESET_SYSCON_REBOOT is not set +CONFIG_RT_POWER_RESET_REBOOT_SPACEMIT=y +# CONFIG_RT_USING_POWER_SUPPLY is not set +CONFIG_RT_USING_THERMAL=y + +# +# Thermal Sensors Drivers +# +CONFIG_RT_THERMAL_K1X=y + +# +# Thermal Cool Drivers +# +CONFIG_RT_THERMAL_COOL_DVFS=y +# CONFIG_RT_THERMAL_COOL_GPIO_FAN is not set +CONFIG_RT_THERMAL_COOL_PWM_FAN=y +CONFIG_RT_USING_VIRTIO=y +# CONFIG_RT_VIRTIO_TRANSPORT_MMIO is not set +# CONFIG_RT_VIRTIO_TRANSPORT_PCI is not set +CONFIG_RT_VIRTIO_NET=y +# CONFIG_RT_VIRTIO_BLK is not set +# CONFIG_RT_VIRTIO_CONSOLE is not set +# CONFIG_RT_VIRTIO_RNG is not set +CONFIG_RT_VIRTIO_RPMSG=y +# CONFIG_RT_VIRTIO_SCSI is not set +# CONFIG_RT_VIRTIO_9P is not set +# CONFIG_RT_VIRTIO_RPROC_SERIAL is not set +# CONFIG_RT_VIRTIO_GPU is not set +# CONFIG_RT_VIRTIO_SOUND is not set +CONFIG_RT_USING_NVMEM=y +CONFIG_RT_NVMEM_SPACEMIT_EFUSE=y +CONFIG_RT_USING_DMA=y +# CONFIG_RT_DMA_PL330 is not set +# CONFIG_RT_DMA_DW_AXI_DMAC is not set +CONFIG_RT_DMA_MMP_PDMA=y +CONFIG_RT_DMA_MMP_PDMA_SUPPORT_64BIT=y +CONFIG_RT_USING_MFD=y +# CONFIG_RT_MFD_EDU is not set +CONFIG_RT_MFD_SYSCON=y +CONFIG_RT_MFD_SPACEMIT_PMIC=y +# CONFIG_RT_USING_IVSHMEM is not set +CONFIG_RT_USING_OFW=y +# CONFIG_RT_USING_BUILTIN_FDT is not set +CONFIG_RT_FDT_EARLYCON_MSG_SIZE=128 +CONFIG_RT_USING_OFW_BUS_RANGES_NUMBER=8 +CONFIG_RT_USING_PCI=y +CONFIG_RT_PCI_MSI=y +CONFIG_RT_PCI_ENDPOINT=y +CONFIG_RT_PCI_SYS_64BIT=y +CONFIG_RT_PCI_CACHE_LINE_SIZE=8 +# CONFIG_RT_PCI_LOCKLESS is not set + +# +# PCI Device Drivers +# +# CONFIG_RT_PCI_ECAM is not set +CONFIG_RT_PCI_DW=y +CONFIG_RT_PCI_DW_HOST=y +CONFIG_RT_PCI_DW_EP=y +CONFIG_RT_PCI_DW_SPACEMIT_K1X=y +CONFIG_RT_USING_PIC=y +# CONFIG_RT_USING_PIC_STATISTICS is not set +CONFIG_MAX_HANDLERS=1024 +# CONFIG_RT_PIC_ARM_GIC is not set +# CONFIG_RT_PIC_ARM_GIC_V3 is not set +# CONFIG_RT_PIC_RISCV_AIA is not set +# CONFIG_RT_PIC_RISCV_CLIC is not set +CONFIG_RT_PIC_RISCV_INTC=y +CONFIG_RT_PIC_SIFIVE_PLIC=y +CONFIG_RT_USING_PIN=y +# CONFIG_RT_PIN_PL061 is not set +CONFIG_RT_PIN_K1X=y +CONFIG_RT_USING_PINCTRL=y +CONFIG_RT_PINCTRL_SINGLE=y +CONFIG_RT_PINCTRL_SPACEMIT_PMIC=y +CONFIG_RT_USING_CLK=y +CONFIG_RT_CLK_SPACEMIT=y +CONFIG_RT_CLK_SPACEMIT_K1X=y +# CONFIG_RT_USING_CHERRYUSB is not set + +# +# SoC (System on Chip) Drivers +# +CONFIG_RT_SOC_SPACEMIT_K1X_RPROC=y +CONFIG_RT_SOC_CHIP_MEDIA_JPU=y +CONFIG_RT_SOC_SPACEMIT_V2D=y +CONFIG_RT_SOC_SPACEMIT_K1X_TCM=y +CONFIG_RT_SOC_SPACEMIT_SOCINFO=y +# end of SoC (System on Chip) Drivers +# end of Device Drivers + +# +# C/C++ and POSIX layer +# + +# +# ISO-ANSI C layer +# + +# +# Timezone and Daylight Saving Time +# +# CONFIG_RT_LIBC_USING_FULL_TZ_DST is not set +CONFIG_RT_LIBC_USING_LIGHT_TZ_DST=y +CONFIG_RT_LIBC_TZ_DEFAULT_HOUR=8 +CONFIG_RT_LIBC_TZ_DEFAULT_MIN=0 +CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0 +# end of Timezone and Daylight Saving Time +# end of ISO-ANSI C layer + +# +# POSIX (Portable Operating System Interface) layer +# +CONFIG_RT_USING_POSIX_FS=y +CONFIG_RT_USING_POSIX_DEVIO=y +CONFIG_RT_USING_POSIX_STDIO=y +CONFIG_RT_USING_POSIX_POLL=y +CONFIG_RT_USING_POSIX_SELECT=y +# CONFIG_RT_USING_POSIX_EVENTFD is not set +# CONFIG_RT_USING_POSIX_TIMERFD is not set +# CONFIG_RT_USING_POSIX_SOCKET is not set +CONFIG_RT_USING_POSIX_TERMIOS=y +CONFIG_RT_USING_POSIX_AIO=y +# CONFIG_RT_USING_POSIX_MMAN is not set +CONFIG_RT_USING_POSIX_DELAY=y +CONFIG_RT_USING_POSIX_CLOCK=y +CONFIG_RT_USING_POSIX_TIMER=y +# CONFIG_RT_USING_PTHREADS is not set +# CONFIG_RT_USING_MODULE is not set + +# +# Interprocess Communication (IPC) +# +CONFIG_RT_USING_POSIX_PIPE=y +CONFIG_RT_USING_POSIX_PIPE_SIZE=512 +# CONFIG_RT_USING_POSIX_MESSAGE_QUEUE is not set +# CONFIG_RT_USING_POSIX_MESSAGE_SEMAPHORE is not set + +# +# Socket is in the 'Network' category +# +# end of Interprocess Communication (IPC) +# end of POSIX (Portable Operating System Interface) layer + +# CONFIG_RT_USING_CPLUSPLUS is not set +# end of C/C++ and POSIX layer + +# +# Network +# +CONFIG_RT_USING_SAL=y +CONFIG_SAL_INTERNET_CHECK=y +CONFIG_SOCKET_TABLE_STEP_LEN=4 + +# +# Docking with protocol stacks +# +CONFIG_SAL_USING_LWIP=y +# CONFIG_SAL_USING_AT is not set +# CONFIG_SAL_USING_TLS is not set +# end of Docking with protocol stacks + +CONFIG_SAL_USING_POSIX=y +# CONFIG_RT_USING_AF_UNIX is not set +CONFIG_RT_USING_NETDEV=y +CONFIG_NETDEV_USING_IFCONFIG=y +CONFIG_NETDEV_USING_PING=y +CONFIG_NETDEV_USING_NETSTAT=y +CONFIG_NETDEV_USING_AUTO_DEFAULT=y +# CONFIG_NETDEV_USING_LINK_STATUS_CALLBACK is not set +# CONFIG_NETDEV_USING_IPV6 is not set +CONFIG_NETDEV_IPV4=1 +CONFIG_NETDEV_IPV6=0 +CONFIG_RT_USING_LWIP=y +# CONFIG_RT_USING_LWIP_LOCAL_VERSION is not set +# CONFIG_RT_USING_LWIP141 is not set +CONFIG_RT_USING_LWIP203=y +# CONFIG_RT_USING_LWIP212 is not set +# CONFIG_RT_USING_LWIP_LATEST is not set +CONFIG_RT_USING_LWIP_VER_NUM=0x20003 +# CONFIG_RT_USING_LWIP_IPV6 is not set +CONFIG_RT_LWIP_MEM_ALIGNMENT=4 +CONFIG_RT_LWIP_IGMP=y +CONFIG_RT_LWIP_ICMP=y +# CONFIG_RT_LWIP_SNMP is not set +CONFIG_RT_LWIP_DNS=y +CONFIG_RT_LWIP_DHCP=y +CONFIG_IP_SOF_BROADCAST=1 +CONFIG_IP_SOF_BROADCAST_RECV=1 + +# +# Static IPv4 Address +# +CONFIG_RT_LWIP_IPADDR="192.168.1.30" +CONFIG_RT_LWIP_GWADDR="192.168.1.1" +CONFIG_RT_LWIP_MSKADDR="255.255.255.0" +# end of Static IPv4 Address + +CONFIG_RT_LWIP_UDP=y +CONFIG_RT_LWIP_TCP=y +CONFIG_RT_LWIP_RAW=y +# CONFIG_RT_LWIP_PPP is not set +CONFIG_RT_MEMP_NUM_NETCONN=8 +CONFIG_RT_LWIP_PBUF_NUM=16 +CONFIG_RT_LWIP_RAW_PCB_NUM=4 +CONFIG_RT_LWIP_UDP_PCB_NUM=4 +CONFIG_RT_LWIP_TCP_PCB_NUM=4 +CONFIG_RT_LWIP_TCP_SEG_NUM=40 +CONFIG_RT_LWIP_TCP_SND_BUF=8196 +CONFIG_RT_LWIP_TCP_WND=8196 +CONFIG_RT_LWIP_TCPTHREAD_PRIORITY=10 +CONFIG_RT_LWIP_TCPTHREAD_MBOX_SIZE=8 +CONFIG_RT_LWIP_TCPTHREAD_STACKSIZE=8192 +# CONFIG_LWIP_NO_RX_THREAD is not set +# CONFIG_LWIP_NO_TX_THREAD is not set +CONFIG_RT_LWIP_ETHTHREAD_PRIORITY=12 +CONFIG_RT_LWIP_ETHTHREAD_STACKSIZE=8192 +CONFIG_RT_LWIP_ETHTHREAD_MBOX_SIZE=8 +# CONFIG_RT_LWIP_REASSEMBLY_FRAG is not set +CONFIG_LWIP_NETIF_STATUS_CALLBACK=1 +CONFIG_LWIP_NETIF_LINK_CALLBACK=1 +CONFIG_RT_LWIP_NETIF_NAMESIZE=6 +CONFIG_SO_REUSE=1 +CONFIG_LWIP_SO_RCVTIMEO=1 +CONFIG_LWIP_SO_SNDTIMEO=1 +CONFIG_LWIP_SO_RCVBUF=1 +CONFIG_LWIP_SO_LINGER=0 +# CONFIG_RT_LWIP_NETIF_LOOPBACK is not set +CONFIG_LWIP_NETIF_LOOPBACK=0 +# CONFIG_RT_LWIP_STATS is not set +# CONFIG_RT_LWIP_USING_HW_CHECKSUM is not set +CONFIG_RT_LWIP_USING_PING=y +# CONFIG_LWIP_USING_DHCPD is not set +# CONFIG_RT_LWIP_ENABLE_USER_HOOKS is not set +# CONFIG_RT_LWIP_DEBUG is not set +# CONFIG_RT_USING_AT is not set +# end of Network + +# +# Memory protection +# +# CONFIG_RT_USING_MEM_PROTECTION is not set +# CONFIG_RT_USING_HW_STACK_GUARD is not set +# end of Memory protection + +# +# Utilities +# +# CONFIG_RT_USING_RYM is not set +# CONFIG_RT_USING_ULOG is not set +# CONFIG_RT_USING_UTEST is not set +# CONFIG_RT_USING_VAR_EXPORT is not set +CONFIG_RT_USING_RESOURCE_ID=y +CONFIG_RT_USING_ADT=y +CONFIG_RT_USING_ADT_AVL=y +CONFIG_RT_USING_ADT_BITMAP=y +CONFIG_RT_USING_ADT_HASHMAP=y +CONFIG_RT_USING_ADT_REF=y +# CONFIG_RT_USING_RT_LINK is not set +# end of Utilities + +# +# Memory management +# +CONFIG_RT_PAGE_MPR_SIZE_DYNAMIC=y +CONFIG_RT_PAGE_AFFINITY_BLOCK_SIZE=0x1000 +CONFIG_RT_PAGE_MAX_ORDER=11 +CONFIG_RT_USING_MEMBLOCK=y +CONFIG_RT_INIT_MEMORY_REGIONS=128 + +# +# Debugging +# +# CONFIG_RT_DEBUGGING_ALIASING is not set +# CONFIG_RT_DEBUGING_PAGE_LEAK is not set +# CONFIG_RT_DEBUGGING_PAGE_POISON is not set +# end of Debugging +# end of Memory management + +# +# Using USB legacy version +# +# CONFIG_RT_USING_USB_HOST is not set +# CONFIG_RT_USING_USB_DEVICE is not set +# end of Using USB legacy version + +# CONFIG_RT_USING_FDT is not set +# CONFIG_RT_USING_LEGACY_VIRTIO is not set +# CONFIG_RT_USING_RUST is not set +# end of RT-Thread Components + +# +# RT-Thread Utestcases +# +# CONFIG_RT_USING_UTESTCASES is not set +# end of RT-Thread Utestcases + +# +# RT-Thread online packages +# + +# +# IoT - internet of things +# +# CONFIG_PKG_USING_LORAWAN_DRIVER is not set +# CONFIG_PKG_USING_PAHOMQTT is not set +# CONFIG_PKG_USING_UMQTT is not set +# CONFIG_PKG_USING_WEBCLIENT is not set +# CONFIG_PKG_USING_WEBNET is not set +# CONFIG_PKG_USING_MONGOOSE is not set +# CONFIG_PKG_USING_MYMQTT is not set +# CONFIG_PKG_USING_KAWAII_MQTT is not set +# CONFIG_PKG_USING_BC28_MQTT is not set +# CONFIG_PKG_USING_WEBTERMINAL is not set +# CONFIG_PKG_USING_FREEMODBUS is not set +# CONFIG_PKG_USING_NANOPB is not set +# CONFIG_PKG_USING_WIFI_HOST_DRIVER is not set +# CONFIG_PKG_USING_ESP_HOSTED is not set + +# +# Wi-Fi +# + +# +# Marvell WiFi +# +# CONFIG_PKG_USING_WLANMARVELL is not set +# end of Marvell WiFi + +# +# Wiced WiFi +# +# CONFIG_PKG_USING_WLAN_WICED is not set +# end of Wiced WiFi + +# CONFIG_PKG_USING_RW007 is not set + +# +# CYW43012 WiFi +# +# CONFIG_PKG_USING_WLAN_CYW43012 is not set +# end of CYW43012 WiFi + +# +# BL808 WiFi +# +# CONFIG_PKG_USING_WLAN_BL808 is not set +# end of BL808 WiFi + +# +# CYW43439 WiFi +# +# CONFIG_PKG_USING_WLAN_CYW43439 is not set +# end of CYW43439 WiFi +# end of Wi-Fi + +# CONFIG_PKG_USING_COAP is not set +# CONFIG_PKG_USING_NOPOLL is not set +# CONFIG_PKG_USING_NETUTILS is not set +# CONFIG_PKG_USING_CMUX is not set +# CONFIG_PKG_USING_PPP_DEVICE is not set +# CONFIG_PKG_USING_AT_DEVICE is not set +# CONFIG_PKG_USING_ATSRV_SOCKET is not set +# CONFIG_PKG_USING_WIZNET is not set +# CONFIG_PKG_USING_ZB_COORDINATOR is not set + +# +# IoT Cloud +# +# CONFIG_PKG_USING_ONENET is not set +# CONFIG_PKG_USING_GAGENT_CLOUD is not set +# CONFIG_PKG_USING_ALI_IOTKIT is not set +# CONFIG_PKG_USING_AZURE is not set +# CONFIG_PKG_USING_TENCENT_IOT_EXPLORER is not set +# CONFIG_PKG_USING_JIOT-C-SDK is not set +# CONFIG_PKG_USING_UCLOUD_IOT_SDK is not set +# CONFIG_PKG_USING_JOYLINK is not set +# CONFIG_PKG_USING_IOTSHARP_SDK is not set +# end of IoT Cloud + +# CONFIG_PKG_USING_NIMBLE is not set +# CONFIG_PKG_USING_LLSYNC_SDK_ADAPTER is not set +# CONFIG_PKG_USING_OTA_DOWNLOADER is not set +# CONFIG_PKG_USING_IPMSG is not set +# CONFIG_PKG_USING_LSSDP is not set +# CONFIG_PKG_USING_AIRKISS_OPEN is not set +# CONFIG_PKG_USING_LIBRWS is not set +# CONFIG_PKG_USING_TCPSERVER is not set +# CONFIG_PKG_USING_PROTOBUF_C is not set +# CONFIG_PKG_USING_DLT645 is not set +# CONFIG_PKG_USING_QXWZ is not set +# CONFIG_PKG_USING_SMTP_CLIENT is not set +# CONFIG_PKG_USING_ABUP_FOTA is not set +# CONFIG_PKG_USING_LIBCURL2RTT is not set +# CONFIG_PKG_USING_CAPNP is not set +# CONFIG_PKG_USING_ERPC is not set +# CONFIG_PKG_USING_AGILE_TELNET is not set +# CONFIG_PKG_USING_NMEALIB is not set +# CONFIG_PKG_USING_PDULIB is not set +# CONFIG_PKG_USING_BTSTACK is not set +# CONFIG_PKG_USING_BT_CYW43012 is not set +# CONFIG_PKG_USING_CYW43XX is not set +# CONFIG_PKG_USING_LORAWAN_ED_STACK is not set +# CONFIG_PKG_USING_WAYZ_IOTKIT is not set +# CONFIG_PKG_USING_MAVLINK is not set +# CONFIG_PKG_USING_BSAL is not set +# CONFIG_PKG_USING_AGILE_MODBUS is not set +# CONFIG_PKG_USING_AGILE_FTP is not set +# CONFIG_PKG_USING_EMBEDDEDPROTO is not set +# CONFIG_PKG_USING_RT_LINK_HW is not set +# CONFIG_PKG_USING_RYANMQTT is not set +# CONFIG_PKG_USING_RYANW5500 is not set +# CONFIG_PKG_USING_LORA_PKT_FWD is not set +# CONFIG_PKG_USING_LORA_GW_DRIVER_LIB is not set +# CONFIG_PKG_USING_LORA_PKT_SNIFFER is not set +# CONFIG_PKG_USING_HM is not set +# CONFIG_PKG_USING_SMALL_MODBUS is not set +# CONFIG_PKG_USING_NET_SERVER is not set +# CONFIG_PKG_USING_ZFTP is not set +# CONFIG_PKG_USING_WOL is not set +# CONFIG_PKG_USING_ZEPHYR_POLLING is not set +# CONFIG_PKG_USING_MATTER_ADAPTATION_LAYER is not set +# CONFIG_PKG_USING_LHC_MODBUS is not set +# CONFIG_PKG_USING_QMODBUS is not set +# CONFIG_PKG_USING_PNET is not set +# CONFIG_PKG_USING_OPENER is not set +# CONFIG_PKG_USING_FREEMQTT is not set +# end of IoT - internet of things + +# +# security packages +# +# CONFIG_PKG_USING_MBEDTLS is not set +# CONFIG_PKG_USING_LIBSODIUM is not set +# CONFIG_PKG_USING_LIBHYDROGEN is not set +# CONFIG_PKG_USING_TINYCRYPT is not set +# CONFIG_PKG_USING_TFM is not set +# CONFIG_PKG_USING_YD_CRYPTO is not set +# end of security packages + +# +# language packages +# + +# +# JSON: JavaScript Object Notation, a lightweight data-interchange format +# +# CONFIG_PKG_USING_CJSON is not set +# CONFIG_PKG_USING_LJSON is not set +# CONFIG_PKG_USING_RT_CJSON_TOOLS is not set +# CONFIG_PKG_USING_RAPIDJSON is not set +# CONFIG_PKG_USING_JSMN is not set +# CONFIG_PKG_USING_AGILE_JSMN is not set +# CONFIG_PKG_USING_PARSON is not set +# CONFIG_PKG_USING_RYAN_JSON is not set +# end of JSON: JavaScript Object Notation, a lightweight data-interchange format + +# +# XML: Extensible Markup Language +# +# CONFIG_PKG_USING_SIMPLE_XML is not set +# CONFIG_PKG_USING_EZXML is not set +# end of XML: Extensible Markup Language + +# CONFIG_PKG_USING_LUATOS_SOC is not set +# CONFIG_PKG_USING_LUA is not set +# CONFIG_PKG_USING_JERRYSCRIPT is not set +# CONFIG_PKG_USING_MICROPYTHON is not set +# CONFIG_PKG_USING_PIKASCRIPT is not set +# CONFIG_PKG_USING_RTT_RUST is not set +# end of language packages + +# +# multimedia packages +# + +# +# LVGL: powerful and easy-to-use embedded GUI library +# +# CONFIG_PKG_USING_LVGL is not set +# CONFIG_PKG_USING_LV_MUSIC_DEMO is not set +# CONFIG_PKG_USING_GUI_GUIDER_DEMO is not set +# end of LVGL: powerful and easy-to-use embedded GUI library + +# +# u8g2: a monochrome graphic library +# +# CONFIG_PKG_USING_U8G2_OFFICIAL is not set +# CONFIG_PKG_USING_U8G2 is not set +# end of u8g2: a monochrome graphic library + +# CONFIG_PKG_USING_NES_SIMULATOR is not set +# CONFIG_PKG_USING_OPENMV is not set +# CONFIG_PKG_USING_MUPDF is not set +# CONFIG_PKG_USING_STEMWIN is not set +# CONFIG_PKG_USING_WAVPLAYER is not set +# CONFIG_PKG_USING_TJPGD is not set +# CONFIG_PKG_USING_PDFGEN is not set +# CONFIG_PKG_USING_HELIX is not set +# CONFIG_PKG_USING_AZUREGUIX is not set +# CONFIG_PKG_USING_TOUCHGFX2RTT is not set +# CONFIG_PKG_USING_NUEMWIN is not set +# CONFIG_PKG_USING_MP3PLAYER is not set +# CONFIG_PKG_USING_TINYJPEG is not set +# CONFIG_PKG_USING_UGUI is not set +# CONFIG_PKG_USING_MCURSES is not set +# CONFIG_PKG_USING_TERMBOX is not set +# CONFIG_PKG_USING_VT100 is not set +# CONFIG_PKG_USING_QRCODE is not set +# CONFIG_PKG_USING_GUIENGINE is not set +# CONFIG_PKG_USING_3GPP_AMRNB is not set +# end of multimedia packages + +# +# tools packages +# +# CONFIG_PKG_USING_VECTOR is not set +# CONFIG_PKG_USING_SORCH is not set +# CONFIG_PKG_USING_DICT is not set +# CONFIG_PKG_USING_CMBACKTRACE is not set +# CONFIG_PKG_USING_MCOREDUMP is not set +# CONFIG_PKG_USING_EASYFLASH is not set +# CONFIG_PKG_USING_EASYLOGGER is not set +# CONFIG_PKG_USING_SYSTEMVIEW is not set +# CONFIG_PKG_USING_SEGGER_RTT is not set +# CONFIG_PKG_USING_RTT_AUTO_EXE_CMD is not set +# CONFIG_PKG_USING_RDB is not set +# CONFIG_PKG_USING_ULOG_EASYFLASH is not set +# CONFIG_PKG_USING_LOGMGR is not set +# CONFIG_PKG_USING_ADBD is not set +# CONFIG_PKG_USING_COREMARK is not set +# CONFIG_PKG_USING_DHRYSTONE is not set +# CONFIG_PKG_USING_MEMORYPERF is not set +# CONFIG_PKG_USING_NR_MICRO_SHELL is not set +# CONFIG_PKG_USING_CHINESE_FONT_LIBRARY is not set +# CONFIG_PKG_USING_LUNAR_CALENDAR is not set +# CONFIG_PKG_USING_BS8116A is not set +# CONFIG_PKG_USING_GPS_RMC is not set +# CONFIG_PKG_USING_URLENCODE is not set +# CONFIG_PKG_USING_UMCN is not set +# CONFIG_PKG_USING_LWRB2RTT is not set +# CONFIG_PKG_USING_CPU_USAGE is not set +# CONFIG_PKG_USING_GBK2UTF8 is not set +# CONFIG_PKG_USING_VCONSOLE is not set +# CONFIG_PKG_USING_KDB is not set +# CONFIG_PKG_USING_WAMR is not set +# CONFIG_PKG_USING_MICRO_XRCE_DDS_CLIENT is not set +# CONFIG_PKG_USING_LWLOG is not set +# CONFIG_PKG_USING_ANV_TRACE is not set +# CONFIG_PKG_USING_ANV_MEMLEAK is not set +# CONFIG_PKG_USING_ANV_TESTSUIT is not set +# CONFIG_PKG_USING_ANV_BENCH is not set +# CONFIG_PKG_USING_DEVMEM is not set +# CONFIG_PKG_USING_REGEX is not set +# CONFIG_PKG_USING_MEM_SANDBOX is not set +# CONFIG_PKG_USING_SOLAR_TERMS is not set +# CONFIG_PKG_USING_GAN_ZHI is not set +# CONFIG_PKG_USING_FDT is not set +# CONFIG_PKG_USING_CBOX is not set +# CONFIG_PKG_USING_SNOWFLAKE is not set +# CONFIG_PKG_USING_HASH_MATCH is not set +# CONFIG_PKG_USING_ARMV7M_DWT_TOOL is not set +# CONFIG_PKG_USING_VOFA_PLUS is not set +# CONFIG_PKG_USING_ZDEBUG is not set +# CONFIG_PKG_USING_RVBACKTRACE is not set +# CONFIG_PKG_USING_HPATCHLITE is not set +# CONFIG_PKG_USING_THREAD_METRIC is not set +# CONFIG_PKG_USING_UORB is not set +# CONFIG_PKG_USING_RT_TUNNEL is not set +# CONFIG_PKG_USING_VIRTUAL_TERMINAL is not set +# CONFIG_PKG_USING_FEE is not set +# end of tools packages + +# +# system packages +# + +# +# enhanced kernel services +# +# CONFIG_PKG_USING_RT_MEMCPY_CM is not set +# CONFIG_PKG_USING_RT_KPRINTF_THREADSAFE is not set +# end of enhanced kernel services + +# CONFIG_PKG_USING_AUNITY is not set + +# +# acceleration: Assembly language or algorithmic acceleration packages +# +# CONFIG_PKG_USING_QFPLIB_M0_FULL is not set +# CONFIG_PKG_USING_QFPLIB_M0_TINY is not set +# CONFIG_PKG_USING_QFPLIB_M3 is not set +# end of acceleration: Assembly language or algorithmic acceleration packages + +# +# CMSIS: ARM Cortex-M Microcontroller Software Interface Standard +# +# CONFIG_PKG_USING_CMSIS_5 is not set +# CONFIG_PKG_USING_CMSIS_CORE is not set +# CONFIG_PKG_USING_CMSIS_NN is not set +# CONFIG_PKG_USING_CMSIS_RTOS1 is not set +# CONFIG_PKG_USING_CMSIS_RTOS2 is not set +# end of CMSIS: ARM Cortex-M Microcontroller Software Interface Standard + +# +# Micrium: Micrium software products porting for RT-Thread +# +# CONFIG_PKG_USING_UCOSIII_WRAPPER is not set +# CONFIG_PKG_USING_UCOSII_WRAPPER is not set +# CONFIG_PKG_USING_UC_CRC is not set +# CONFIG_PKG_USING_UC_CLK is not set +# CONFIG_PKG_USING_UC_COMMON is not set +# CONFIG_PKG_USING_UC_MODBUS is not set +# end of Micrium: Micrium software products porting for RT-Thread + +# CONFIG_PKG_USING_FREERTOS_WRAPPER is not set +# CONFIG_PKG_USING_LITEOS_SDK is not set +# CONFIG_PKG_USING_TZ_DATABASE is not set +# CONFIG_PKG_USING_CAIRO is not set +# CONFIG_PKG_USING_PIXMAN is not set +# CONFIG_PKG_USING_PARTITION is not set +# CONFIG_PKG_USING_PERF_COUNTER is not set +# CONFIG_PKG_USING_FILEX is not set +# CONFIG_PKG_USING_LEVELX is not set +# CONFIG_PKG_USING_FLASHDB is not set +# CONFIG_PKG_USING_SQLITE is not set +# CONFIG_PKG_USING_RTI is not set +# CONFIG_PKG_USING_DFS_YAFFS is not set +# CONFIG_PKG_USING_LITTLEFS is not set +# CONFIG_PKG_USING_DFS_JFFS2 is not set +# CONFIG_PKG_USING_DFS_UFFS is not set +# CONFIG_PKG_USING_LWEXT4 is not set +# CONFIG_PKG_USING_THREAD_POOL is not set +# CONFIG_PKG_USING_ROBOTS is not set +# CONFIG_PKG_USING_EV is not set +# CONFIG_PKG_USING_SYSWATCH is not set +# CONFIG_PKG_USING_SYS_LOAD_MONITOR is not set +# CONFIG_PKG_USING_PLCCORE is not set +# CONFIG_PKG_USING_RAMDISK is not set +# CONFIG_PKG_USING_MININI is not set +# CONFIG_PKG_USING_QBOOT is not set +# CONFIG_PKG_USING_PPOOL is not set +# CONFIG_PKG_USING_OPENAMP is not set +# CONFIG_PKG_USING_RPMSG_LITE is not set +# CONFIG_PKG_USING_LPM is not set +# CONFIG_PKG_USING_TLSF is not set +# CONFIG_PKG_USING_EVENT_RECORDER is not set +# CONFIG_PKG_USING_ARM_2D is not set +# CONFIG_PKG_USING_MCUBOOT is not set +# CONFIG_PKG_USING_TINYUSB is not set +# CONFIG_PKG_USING_KMULTI_RTIMER is not set +# CONFIG_PKG_USING_TFDB is not set +# CONFIG_PKG_USING_QPC is not set +# CONFIG_PKG_USING_AGILE_UPGRADE is not set +# CONFIG_PKG_USING_FLASH_BLOB is not set +# CONFIG_PKG_USING_MLIBC is not set +# CONFIG_PKG_USING_TASK_MSG_BUS is not set +# CONFIG_PKG_USING_UART_FRAMEWORK is not set +# CONFIG_PKG_USING_SFDB is not set +# CONFIG_PKG_USING_RTP is not set +# CONFIG_PKG_USING_REB is not set +# CONFIG_PKG_USING_RMP is not set +# CONFIG_PKG_USING_R_RHEALSTONE is not set +# CONFIG_PKG_USING_HEARTBEAT is not set +# CONFIG_PKG_USING_MICRO_ROS_RTTHREAD_PACKAGE is not set +# CONFIG_PKG_USING_CHERRYECAT is not set +# CONFIG_PKG_USING_EVENT_LOOP is not set +# CONFIG_PKG_USING_THREAD_MANAGER is not set +# end of system packages + +# +# peripheral libraries and drivers +# + +# +# HAL & SDK Drivers +# + +# +# STM32 HAL & SDK Drivers +# +# CONFIG_PKG_USING_STM32F0_HAL_DRIVER is not set +# CONFIG_PKG_USING_STM32F0_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_STM32F1_HAL_DRIVER is not set +# CONFIG_PKG_USING_STM32F1_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_STM32F2_HAL_DRIVER is not set +# CONFIG_PKG_USING_STM32F2_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_STM32F3_HAL_DRIVER is not set +# CONFIG_PKG_USING_STM32F3_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_STM32F4_HAL_DRIVER is not set +# CONFIG_PKG_USING_STM32F4_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_STM32F7_HAL_DRIVER is not set +# CONFIG_PKG_USING_STM32F7_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_STM32G0_HAL_DRIVER is not set +# CONFIG_PKG_USING_STM32G0_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_STM32G4_HAL_DRIVER is not set +# CONFIG_PKG_USING_STM32G4_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_STM32H5_HAL_DRIVER is not set +# CONFIG_PKG_USING_STM32H5_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_STM32H7_HAL_DRIVER is not set +# CONFIG_PKG_USING_STM32H7_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_STM32H7RS_HAL_DRIVER is not set +# CONFIG_PKG_USING_STM32H7RS_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_STM32L0_HAL_DRIVER is not set +# CONFIG_PKG_USING_STM32L0_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_STM32L4_HAL_DRIVER is not set +# CONFIG_PKG_USING_STM32L4_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_STM32L5_HAL_DRIVER is not set +# CONFIG_PKG_USING_STM32L5_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_STM32U5_HAL_DRIVER is not set +# CONFIG_PKG_USING_STM32U5_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_STM32WB55_SDK is not set +# CONFIG_PKG_USING_STM32_SDIO is not set +# CONFIG_PKG_USING_STM32WL_HAL_DRIVER is not set +# CONFIG_PKG_USING_STM32WL_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_STM32WB_HAL_DRIVER is not set +# CONFIG_PKG_USING_STM32WB_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_STM32MP1_M4_HAL_DRIVER is not set +# CONFIG_PKG_USING_STM32MP1_M4_CMSIS_DRIVER is not set +# end of STM32 HAL & SDK Drivers + +# +# Infineon HAL Packages +# +# CONFIG_PKG_USING_INFINEON_CAT1CM0P is not set +# CONFIG_PKG_USING_INFINEON_CMSIS is not set +# CONFIG_PKG_USING_INFINEON_CORE_LIB is not set +# CONFIG_PKG_USING_INFINEON_MTB_HAL_CAT1 is not set +# CONFIG_PKG_USING_INFINEON_MTB_PDL_CAT1 is not set +# CONFIG_PKG_USING_INFINEON_RETARGET_IO is not set +# CONFIG_PKG_USING_INFINEON_CAPSENSE is not set +# CONFIG_PKG_USING_INFINEON_CSDIDAC is not set +# CONFIG_PKG_USING_INFINEON_SERIAL_FLASH is not set +# CONFIG_PKG_USING_INFINEON_USBDEV is not set +# end of Infineon HAL Packages + +# CONFIG_PKG_USING_BLUETRUM_SDK is not set +# CONFIG_PKG_USING_EMBARC_BSP is not set +# CONFIG_PKG_USING_ESP_IDF is not set + +# +# Kendryte SDK +# +# CONFIG_PKG_USING_K210_SDK is not set +# CONFIG_PKG_USING_KENDRYTE_SDK is not set +# end of Kendryte SDK + +# CONFIG_PKG_USING_NRF5X_SDK is not set +# CONFIG_PKG_USING_NRFX is not set +# CONFIG_PKG_USING_NUCLEI_SDK is not set +# CONFIG_PKG_USING_RASPBERRYPI_PICO_RP2350_SDK is not set +# CONFIG_PKG_USING_RASPBERRYPI_PICO_SDK is not set + +# +# MM32 HAL & SDK Drivers +# +# CONFIG_PKG_USING_MM32F103XX_CMSIS is not set +# CONFIG_PKG_USING_MM32F3270X_CMSIS is not set +# CONFIG_PKG_USING_MM32F5260X_CMSIS is not set +# CONFIG_PKG_USING_MM32L0XX_CMSIS is not set +# CONFIG_PKG_USING_MM32L3XX_CMSIS is not set +# CONFIG_PKG_USING_MM32F103XX_HAL_DRIVER is not set +# CONFIG_PKG_USING_MM32F3270X_HAL_DRIVER is not set +# CONFIG_PKG_USING_MM32F5260X_HAL_DRIVER is not set +# CONFIG_PKG_USING_MM32L0XX_HAL_DRIVER is not set +# CONFIG_PKG_USING_MM32L3XX_HAL_DRIVER is not set +# end of MM32 HAL & SDK Drivers + +# +# WCH HAL & SDK Drivers +# +# CONFIG_PKG_USING_CH32V20x_SDK is not set +# CONFIG_PKG_USING_CH32V307_SDK is not set +# end of WCH HAL & SDK Drivers + +# +# AT32 HAL & SDK Drivers +# +# CONFIG_PKG_USING_AT32A403A_HAL_DRIVER is not set +# CONFIG_PKG_USING_AT32A403A_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_AT32A423_HAL_DRIVER is not set +# CONFIG_PKG_USING_AT32A423_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_AT32F45x_HAL_DRIVER is not set +# CONFIG_PKG_USING_AT32F45x_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_AT32F402_405_HAL_DRIVER is not set +# CONFIG_PKG_USING_AT32F402_405_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_AT32F403A_407_HAL_DRIVER is not set +# CONFIG_PKG_USING_AT32F403A_407_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_AT32F413_HAL_DRIVER is not set +# CONFIG_PKG_USING_AT32F413_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_AT32F415_HAL_DRIVER is not set +# CONFIG_PKG_USING_AT32F415_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_AT32F421_HAL_DRIVER is not set +# CONFIG_PKG_USING_AT32F421_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_AT32F423_HAL_DRIVER is not set +# CONFIG_PKG_USING_AT32F423_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_AT32F425_HAL_DRIVER is not set +# CONFIG_PKG_USING_AT32F425_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_AT32F435_437_HAL_DRIVER is not set +# CONFIG_PKG_USING_AT32F435_437_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_AT32M412_416_HAL_DRIVER is not set +# CONFIG_PKG_USING_AT32M412_416_CMSIS_DRIVER is not set +# end of AT32 HAL & SDK Drivers + +# +# HC32 DDL Drivers +# +# CONFIG_PKG_USING_HC32F3_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_HC32F3_SERIES_DRIVER is not set +# CONFIG_PKG_USING_HC32F4_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_HC32F4_SERIES_DRIVER is not set +# end of HC32 DDL Drivers + +# +# NXP HAL & SDK Drivers +# +# CONFIG_PKG_USING_NXP_MCX_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_NXP_MCX_SERIES_DRIVER is not set +# CONFIG_PKG_USING_NXP_LPC_DRIVER is not set +# CONFIG_PKG_USING_NXP_LPC55S_DRIVER is not set +# CONFIG_PKG_USING_NXP_IMX6SX_DRIVER is not set +# CONFIG_PKG_USING_NXP_IMX6UL_DRIVER is not set +# CONFIG_PKG_USING_NXP_IMXRT_DRIVER is not set +# end of NXP HAL & SDK Drivers + +# +# NUVOTON Drivers +# +# CONFIG_PKG_USING_NUVOTON_SERIES_DRIVER is not set +# end of NUVOTON Drivers + +# +# GD32 Drivers +# +# CONFIG_PKG_USING_GD32_ARM_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_GD32_ARM_SERIES_DRIVER is not set +# CONFIG_PKG_USING_GD32_RISCV_SERIES_DRIVER is not set +# CONFIG_PKG_USING_GD32VW55X_WIFI is not set +# end of GD32 Drivers + +# +# HPMicro SDK +# +# CONFIG_PKG_USING_HPM_SDK is not set +# end of HPMicro SDK + +# +# FT32 HAL & SDK Drivers +# +# CONFIG_PKG_USING_FT32F0_STD_DRIVER is not set +# CONFIG_PKG_USING_FT32F0_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_FT32F4_STD_DRIVER is not set +# CONFIG_PKG_USING_FT32F4_CMSIS_DRIVER is not set +# end of FT32 HAL & SDK Drivers + +# +# NOVOSNS Drivers +# +# CONFIG_PKG_USING_NOVOSNS_SERIES_DRIVER is not set +# end of NOVOSNS Drivers + +# +# N32 Drivers +# +# CONFIG_PKG_USING_N32H7XX_STD_DRIVER is not set +# CONFIG_PKG_USING_N32H7XX_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_N32H49X_STD_DRIVER is not set +# CONFIG_PKG_USING_N32H49X_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_N32H47X_48X_STD_DRIVER is not set +# CONFIG_PKG_USING_N32H47X_48X_CMSIS_DRIVER is not set +# end of N32 Drivers +# end of HAL & SDK Drivers + +# +# sensors drivers +# +# CONFIG_PKG_USING_LSM6DSM is not set +# CONFIG_PKG_USING_LSM6DSL is not set +# CONFIG_PKG_USING_LPS22HB is not set +# CONFIG_PKG_USING_HTS221 is not set +# CONFIG_PKG_USING_LSM303AGR is not set +# CONFIG_PKG_USING_BME280 is not set +# CONFIG_PKG_USING_BME680 is not set +# CONFIG_PKG_USING_BMA400 is not set +# CONFIG_PKG_USING_BMI160_BMX160 is not set +# CONFIG_PKG_USING_SPL0601 is not set +# CONFIG_PKG_USING_MS5805 is not set +# CONFIG_PKG_USING_DA270 is not set +# CONFIG_PKG_USING_DF220 is not set +# CONFIG_PKG_USING_HSHCAL001 is not set +# CONFIG_PKG_USING_BH1750 is not set +# CONFIG_PKG_USING_MPU6XXX is not set +# CONFIG_PKG_USING_AHT10 is not set +# CONFIG_PKG_USING_AP3216C is not set +# CONFIG_PKG_USING_TSL4531 is not set +# CONFIG_PKG_USING_DS18B20 is not set +# CONFIG_PKG_USING_DHT11 is not set +# CONFIG_PKG_USING_DHTXX is not set +# CONFIG_PKG_USING_GY271 is not set +# CONFIG_PKG_USING_GP2Y10 is not set +# CONFIG_PKG_USING_SGP30 is not set +# CONFIG_PKG_USING_HDC1000 is not set +# CONFIG_PKG_USING_BMP180 is not set +# CONFIG_PKG_USING_BMP280 is not set +# CONFIG_PKG_USING_SHTC1 is not set +# CONFIG_PKG_USING_BMI088 is not set +# CONFIG_PKG_USING_HMC5883 is not set +# CONFIG_PKG_USING_MAX6675 is not set +# CONFIG_PKG_USING_MAX31855 is not set +# CONFIG_PKG_USING_TMP1075 is not set +# CONFIG_PKG_USING_SR04 is not set +# CONFIG_PKG_USING_CCS811 is not set +# CONFIG_PKG_USING_PMSXX is not set +# CONFIG_PKG_USING_RT3020 is not set +# CONFIG_PKG_USING_MLX90632 is not set +# CONFIG_PKG_USING_MLX90382 is not set +# CONFIG_PKG_USING_MLX90384 is not set +# CONFIG_PKG_USING_MLX90393 is not set +# CONFIG_PKG_USING_MLX90392 is not set +# CONFIG_PKG_USING_MLX90394 is not set +# CONFIG_PKG_USING_MLX90396 is not set +# CONFIG_PKG_USING_MLX90397 is not set +# CONFIG_PKG_USING_MS5611 is not set +# CONFIG_PKG_USING_MAX31865 is not set +# CONFIG_PKG_USING_VL53L0X is not set +# CONFIG_PKG_USING_INA260 is not set +# CONFIG_PKG_USING_MAX30102 is not set +# CONFIG_PKG_USING_INA226 is not set +# CONFIG_PKG_USING_LIS2DH12 is not set +# CONFIG_PKG_USING_HS300X is not set +# CONFIG_PKG_USING_ZMOD4410 is not set +# CONFIG_PKG_USING_ISL29035 is not set +# CONFIG_PKG_USING_MMC3680KJ is not set +# CONFIG_PKG_USING_QMP6989 is not set +# CONFIG_PKG_USING_BALANCE is not set +# CONFIG_PKG_USING_SHT2X is not set +# CONFIG_PKG_USING_SHT3X is not set +# CONFIG_PKG_USING_SHT4X is not set +# CONFIG_PKG_USING_AD7746 is not set +# CONFIG_PKG_USING_ADT74XX is not set +# CONFIG_PKG_USING_MAX17048 is not set +# CONFIG_PKG_USING_AS7341 is not set +# CONFIG_PKG_USING_CW2015 is not set +# CONFIG_PKG_USING_ICM20608 is not set +# CONFIG_PKG_USING_PAJ7620 is not set +# CONFIG_PKG_USING_STHS34PF80 is not set +# CONFIG_PKG_USING_P3T1755 is not set +# CONFIG_PKG_USING_QMI8658 is not set +# CONFIG_PKG_USING_ICM20948 is not set +# CONFIG_PKG_USING_SCD4X is not set +# end of sensors drivers + +# +# touch drivers +# +# CONFIG_PKG_USING_GT9147 is not set +# CONFIG_PKG_USING_GT1151 is not set +# CONFIG_PKG_USING_GT917S is not set +# CONFIG_PKG_USING_GT911 is not set +# CONFIG_PKG_USING_FT6206 is not set +# CONFIG_PKG_USING_FT5426 is not set +# CONFIG_PKG_USING_FT6236 is not set +# CONFIG_PKG_USING_XPT2046_TOUCH is not set +# CONFIG_PKG_USING_CST816X is not set +# CONFIG_PKG_USING_CST812T is not set +# end of touch drivers + +# CONFIG_PKG_USING_LCD_SPI_DRIVER is not set +# CONFIG_PKG_USING_REALTEK_AMEBA is not set +# CONFIG_PKG_USING_BUTTON is not set +# CONFIG_PKG_USING_PCF8574 is not set +# CONFIG_PKG_USING_SX12XX is not set +# CONFIG_PKG_USING_SIGNAL_LED is not set +# CONFIG_PKG_USING_LEDBLINK is not set +# CONFIG_PKG_USING_LITTLED is not set +# CONFIG_PKG_USING_LKDGUI is not set +# CONFIG_PKG_USING_INFRARED is not set +# CONFIG_PKG_USING_MULTI_INFRARED is not set +# CONFIG_PKG_USING_AGILE_BUTTON is not set +# CONFIG_PKG_USING_AGILE_LED is not set +# CONFIG_PKG_USING_AT24CXX is not set +# CONFIG_PKG_USING_MOTIONDRIVER2RTT is not set +# CONFIG_PKG_USING_PCA9685 is not set +# CONFIG_PKG_USING_ILI9341 is not set +# CONFIG_PKG_USING_I2C_TOOLS is not set +# CONFIG_PKG_USING_NRF24L01 is not set +# CONFIG_PKG_USING_RPLIDAR is not set +# CONFIG_PKG_USING_AS608 is not set +# CONFIG_PKG_USING_RC522 is not set +# CONFIG_PKG_USING_WS2812B is not set +# CONFIG_PKG_USING_EXTERN_RTC_DRIVERS is not set +# CONFIG_PKG_USING_MULTI_RTIMER is not set +# CONFIG_PKG_USING_MAX7219 is not set +# CONFIG_PKG_USING_BEEP is not set +# CONFIG_PKG_USING_EASYBLINK is not set +# CONFIG_PKG_USING_PMS_SERIES is not set +# CONFIG_PKG_USING_CAN_YMODEM is not set +# CONFIG_PKG_USING_LORA_RADIO_DRIVER is not set +# CONFIG_PKG_USING_QLED is not set +# CONFIG_PKG_USING_AGILE_CONSOLE is not set +# CONFIG_PKG_USING_LD3320 is not set +# CONFIG_PKG_USING_WK2124 is not set +# CONFIG_PKG_USING_LY68L6400 is not set +# CONFIG_PKG_USING_DM9051 is not set +# CONFIG_PKG_USING_CH390 is not set +# CONFIG_PKG_USING_SSD1306 is not set +# CONFIG_PKG_USING_QKEY is not set +# CONFIG_PKG_USING_RS485 is not set +# CONFIG_PKG_USING_RS232 is not set +# CONFIG_PKG_USING_NES is not set +# CONFIG_PKG_USING_VIRTUAL_SENSOR is not set +# CONFIG_PKG_USING_VDEVICE is not set +# CONFIG_PKG_USING_SGM706 is not set +# CONFIG_PKG_USING_RDA58XX is not set +# CONFIG_PKG_USING_LIBNFC is not set +# CONFIG_PKG_USING_MFOC is not set +# CONFIG_PKG_USING_TMC51XX is not set +# CONFIG_PKG_USING_TCA9534 is not set +# CONFIG_PKG_USING_KOBUKI is not set +# CONFIG_PKG_USING_ROSSERIAL is not set +# CONFIG_PKG_USING_MICRO_ROS is not set +# CONFIG_PKG_USING_MCP23008 is not set +# CONFIG_PKG_USING_MISAKA_AT24CXX is not set +# CONFIG_PKG_USING_MISAKA_RGB_BLING is not set +# CONFIG_PKG_USING_LORA_MODEM_DRIVER is not set +# CONFIG_PKG_USING_SOFT_SERIAL is not set +# CONFIG_PKG_USING_MB85RS16 is not set +# CONFIG_PKG_USING_RFM300 is not set +# CONFIG_PKG_USING_IO_INPUT_FILTER is not set +# CONFIG_PKG_USING_LRF_NV7LIDAR is not set +# CONFIG_PKG_USING_AIP650 is not set +# CONFIG_PKG_USING_FINGERPRINT is not set +# CONFIG_PKG_USING_BT_ECB02C is not set +# CONFIG_PKG_USING_UAT is not set +# CONFIG_PKG_USING_ST7789 is not set +# CONFIG_PKG_USING_VS1003 is not set +# CONFIG_PKG_USING_X9555 is not set +# CONFIG_PKG_USING_SYSTEM_RUN_LED is not set +# CONFIG_PKG_USING_BT_MX01 is not set +# CONFIG_PKG_USING_RGPOWER is not set +# CONFIG_PKG_USING_BT_MX02 is not set +# CONFIG_PKG_USING_GC9A01 is not set +# CONFIG_PKG_USING_IK485 is not set +# CONFIG_PKG_USING_SERVO is not set +# CONFIG_PKG_USING_SEAN_WS2812B is not set +# CONFIG_PKG_USING_IC74HC165 is not set +# CONFIG_PKG_USING_IST8310 is not set +# CONFIG_PKG_USING_ST7789_SPI is not set +# CONFIG_PKG_USING_CAN_UDS is not set +# CONFIG_PKG_USING_ISOTP_C is not set +# CONFIG_PKG_USING_IKUNLED is not set +# CONFIG_PKG_USING_INS5T8025 is not set +# CONFIG_PKG_USING_IRUART is not set +# CONFIG_PKG_USING_ST7305 is not set +# CONFIG_PKG_USING_TM1668 is not set +# CONFIG_PKG_USING_TCA9548A is not set +# CONFIG_PKG_USING_SPI_TOOLS is not set +# end of peripheral libraries and drivers + +# +# AI packages +# +# CONFIG_PKG_USING_LIBANN is not set +# CONFIG_PKG_USING_NNOM is not set +# CONFIG_PKG_USING_ONNX_BACKEND is not set +# CONFIG_PKG_USING_ONNX_PARSER is not set +# CONFIG_PKG_USING_TENSORFLOWLITEMICRO is not set +# CONFIG_PKG_USING_ELAPACK is not set +# CONFIG_PKG_USING_ULAPACK is not set +# CONFIG_PKG_USING_QUEST is not set +# CONFIG_PKG_USING_NAXOS is not set +# CONFIG_PKG_USING_R_TINYMAIX is not set +# CONFIG_PKG_USING_LLMCHAT is not set +# CONFIG_PKG_USING_AIFES is not set +# CONFIG_PKG_USING_AGENT is not set +# end of AI packages + +# +# Signal Processing and Control Algorithm Packages +# +# CONFIG_PKG_USING_APID is not set +# CONFIG_PKG_USING_FIRE_PID_CURVE is not set +# CONFIG_PKG_USING_QPID is not set +# CONFIG_PKG_USING_UKAL is not set +# CONFIG_PKG_USING_DIGITALCTRL is not set +# CONFIG_PKG_USING_KISSFFT is not set +# end of Signal Processing and Control Algorithm Packages + +# +# miscellaneous packages +# + +# +# project laboratory +# +# end of project laboratory + +# +# samples: kernel and components samples +# +# CONFIG_PKG_USING_KERNEL_SAMPLES is not set +# CONFIG_PKG_USING_FILESYSTEM_SAMPLES is not set +# CONFIG_PKG_USING_NETWORK_SAMPLES is not set +# CONFIG_PKG_USING_PERIPHERAL_SAMPLES is not set +# end of samples: kernel and components samples + +# +# entertainment: terminal games and other interesting software packages +# +# CONFIG_PKG_USING_CMATRIX is not set +# CONFIG_PKG_USING_SL is not set +# CONFIG_PKG_USING_CAL is not set +# CONFIG_PKG_USING_ACLOCK is not set +# CONFIG_PKG_USING_THREES is not set +# CONFIG_PKG_USING_2048 is not set +# CONFIG_PKG_USING_SNAKE is not set +# CONFIG_PKG_USING_TETRIS is not set +# CONFIG_PKG_USING_DONUT is not set +# CONFIG_PKG_USING_COWSAY is not set +# CONFIG_PKG_USING_MORSE is not set +# end of entertainment: terminal games and other interesting software packages + +# CONFIG_PKG_USING_LIBCSV is not set +# CONFIG_PKG_USING_OPTPARSE is not set +# CONFIG_PKG_USING_FASTLZ is not set +# CONFIG_PKG_USING_MINILZO is not set +# CONFIG_PKG_USING_QUICKLZ is not set +# CONFIG_PKG_USING_LZMA is not set +# CONFIG_PKG_USING_RALARAM is not set +# CONFIG_PKG_USING_MULTIBUTTON is not set +# CONFIG_PKG_USING_FLEXIBLE_BUTTON is not set +# CONFIG_PKG_USING_CANFESTIVAL is not set +# CONFIG_PKG_USING_ZLIB is not set +# CONFIG_PKG_USING_MINIZIP is not set +# CONFIG_PKG_USING_HEATSHRINK is not set +# CONFIG_PKG_USING_DSTR is not set +# CONFIG_PKG_USING_TINYFRAME is not set +# CONFIG_PKG_USING_KENDRYTE_DEMO is not set +# CONFIG_PKG_USING_UPACKER is not set +# CONFIG_PKG_USING_UPARAM is not set +# CONFIG_PKG_USING_HELLO is not set +# CONFIG_PKG_USING_VI is not set +# CONFIG_PKG_USING_KI is not set +# CONFIG_PKG_USING_ARMv7M_DWT is not set +# CONFIG_PKG_USING_CRCLIB is not set +# CONFIG_PKG_USING_LIBCRC is not set +# CONFIG_PKG_USING_LWGPS is not set +# CONFIG_PKG_USING_STATE_MACHINE is not set +# CONFIG_PKG_USING_DESIGN_PATTERN is not set +# CONFIG_PKG_USING_CONTROLLER is not set +# CONFIG_PKG_USING_PHASE_LOCKED_LOOP is not set +# CONFIG_PKG_USING_MFBD is not set +# CONFIG_PKG_USING_SLCAN2RTT is not set +# CONFIG_PKG_USING_SOEM is not set +# CONFIG_PKG_USING_QPARAM is not set +# CONFIG_PKG_USING_CorevMCU_CLI is not set +# CONFIG_PKG_USING_DRMP is not set +# CONFIG_PKG_USING_AUTOGEN_PARAMETER_MANAGER is not set +# end of miscellaneous packages + +# +# Arduino libraries +# +# CONFIG_PKG_USING_RTDUINO is not set + +# +# Projects and Demos +# +# CONFIG_PKG_USING_ARDUINO_MSGQ_C_CPP_DEMO is not set +# CONFIG_PKG_USING_ARDUINO_SKETCH_LOADER_DEMO is not set +# CONFIG_PKG_USING_ARDUINO_ULTRASOUND_RADAR is not set +# CONFIG_PKG_USING_ARDUINO_RTDUINO_SENSORFUSION_SHIELD is not set +# CONFIG_PKG_USING_ARDUINO_NINEINONE_SENSOR_SHIELD is not set +# CONFIG_PKG_USING_ARDUINO_SENSOR_KIT is not set +# CONFIG_PKG_USING_ARDUINO_MATLAB_SUPPORT is not set +# end of Projects and Demos + +# +# Sensors +# +# CONFIG_PKG_USING_ARDUINO_SENSOR_DEVICE_DRIVERS is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SENSOR is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SENSORLAB is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_ADXL375 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_VL53L0X is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_VL53L1X is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_VL6180X is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MAX31855 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MAX31865 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MAX31856 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MAX6675 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MLX90614 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LSM9DS1 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_AHTX0 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LSM9DS0 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BMP280 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_ADT7410 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BMP085 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BME680 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MCP9808 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MCP4728 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_INA219 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LTR390 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_ADXL345 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_DHT is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MCP9600 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LSM6DS is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BNO055 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MAX1704X is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MMC56X3 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MLX90393 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MLX90395 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_ICM20X is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_DPS310 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_HTS221 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SHT4X is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SHT31 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_ADXL343 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BME280 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_AS726X is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_AMG88XX is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_AM2320 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_AM2315 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LTR329_LTR303 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BMP085_UNIFIED is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BMP183 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BMP183_UNIFIED is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BMP3XX is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MS8607 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LIS3MDL is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MLX90640 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MMA8451 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MSA301 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MPL115A2 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BNO08X is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BNO08X_RVC is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LIS2MDL is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LSM303DLH_MAG is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LC709203F is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_CAP1188 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_CCS811 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_NAU7802 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LIS331 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LPS2X is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LPS35HW is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LSM303_ACCEL is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LIS3DH is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_PCF8591 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MPL3115A2 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MPR121 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MPRLS is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MPU6050 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_PCT2075 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_PM25AQI is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_EMC2101 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_FXAS21002C is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SCD30 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_FXOS8700 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_HMC5883_UNIFIED is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SGP30 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_TMP006 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_TLA202X is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_TCS34725 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SI7021 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SI1145 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SGP40 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SHTC3 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_HDC1000 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_HTU21DF is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_AS7341 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_HTU31D is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_INA260 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_TMP007_LIBRARY is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_L3GD20 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_TMP117 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_TSC2007 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_TSL2561 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_TSL2591_LIBRARY is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_VCNL4040 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_VEML6070 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_VEML6075 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_VEML7700 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_LIS3DHTR is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_DHT is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_ADXL335 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_ADXL345 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_BME280 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_BMP280 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_H3LIS331DL is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_MMA7660 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_TSL2561 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_PAJ7620 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_VL53L0X is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_ITG3200 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_SHT31 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_HP20X is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_DRV2605L is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_BBM150 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_HMC5883L is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_LSM303DLH is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_TCS3414CS is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_MP503 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_BMP085 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_HIGHTEMP is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_VEML6070 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_SI1145 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_SHT35 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_AT42QT1070 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_LSM6DS3 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_HDC1000 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_HM3301 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_MCP9600 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_LTC2941 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_LDC1612 is not set +# CONFIG_PKG_USING_ARDUINO_CAPACITIVESENSOR is not set +# CONFIG_PKG_USING_ARDUINO_JARZEBSKI_MPU6050 is not set +# end of Sensors + +# +# Display +# +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_GFX_LIBRARY is not set +# CONFIG_PKG_USING_ARDUINO_U8G2 is not set +# CONFIG_PKG_USING_ARDUINO_TFT_ESPI is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_ST7735 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SSD1306 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_ILI9341 is not set +# CONFIG_PKG_USING_SEEED_TM1637 is not set +# end of Display + +# +# Timing +# +# CONFIG_PKG_USING_ARDUINO_RTCLIB is not set +# CONFIG_PKG_USING_ARDUINO_MSTIMER2 is not set +# CONFIG_PKG_USING_ARDUINO_TICKER is not set +# CONFIG_PKG_USING_ARDUINO_TASKSCHEDULER is not set +# end of Timing + +# +# Data Processing +# +# CONFIG_PKG_USING_ARDUINO_KALMANFILTER is not set +# CONFIG_PKG_USING_ARDUINO_ARDUINOJSON is not set +# CONFIG_PKG_USING_ARDUINO_TENSORFLOW_LITE_MICRO is not set +# CONFIG_PKG_USING_ARDUINO_RUNNINGMEDIAN is not set +# end of Data Processing + +# +# Data Storage +# + +# +# Communication +# +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_PN532 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SI4713 is not set +# end of Communication + +# +# Device Control +# +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_PCF8574 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_PCA9685 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_TPA2016 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_DRV2605 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_DS1841 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_DS3502 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_PCF85063TP is not set +# end of Device Control + +# +# Other +# +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MFRC630 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SI5351 is not set +# end of Other + +# +# Signal IO +# +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BUSIO is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_TCA8418 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MCP23017 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_ADS1X15 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_AW9523 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MCP3008 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MCP4725 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BD3491FS is not set +# end of Signal IO + +# +# Uncategorized +# +# end of Arduino libraries +# end of RT-Thread online packages + +CONFIG_SOC_SPACEMIT_K1=y diff --git a/bsp/spacemit/k1/.gitignore b/bsp/spacemit/k1/.gitignore new file mode 100644 index 000000000000..d7cc9e21eb56 --- /dev/null +++ b/bsp/spacemit/k1/.gitignore @@ -0,0 +1,8 @@ +__pycache__/ +build/ +*.bin +*.elf +!drivers/esos.elf +*.map +*.old +.sconsign.dblite diff --git a/bsp/spacemit/k1/Kconfig b/bsp/spacemit/k1/Kconfig new file mode 100644 index 000000000000..3b10d0d775a9 --- /dev/null +++ b/bsp/spacemit/k1/Kconfig @@ -0,0 +1,27 @@ +mainmenu "RT-Thread Project Configuration" + +BSP_DIR := . + +RTT_DIR := ../../.. + +PKGS_DIR := packages + +SOC_DM_DIR := $BSP_DIR/../dm/ + +source "$(SOC_DM_DIR)/Kconfig" +source "$(RTT_DIR)/Kconfig" +osource "$PKGS_DIR/Kconfig" + +config SOC_SPACEMIT_K1 + bool + select ARCH_RISCV64 + select RT_USING_RISCV_NEW_COMMON + select RT_USING_COMPONENTS_INIT + select RT_USING_USER_MAIN + select RT_USING_CACHE + select ARCH_MM_MMU + select ARCH_REMAP_KERNEL if RT_USING_SMART + select ARCH_RISCV_FPU_D + select RT_USING_CPU_FFS + select RT_USING_STDC_ATOMIC + default y diff --git a/bsp/spacemit/k1/README.md b/bsp/spacemit/k1/README.md new file mode 100644 index 000000000000..2166defca55e --- /dev/null +++ b/bsp/spacemit/k1/README.md @@ -0,0 +1,182 @@ +[English](README_en.md) | **中文** + +# SpacemiT K1 BSP + +## 1. 简介 + +本 BSP 将 RT-Thread 标准版移植到 SpacemiT K1 64 位 RISC-V SoC。当前启动方式仅在 +**Banana Pi BPI-F3 SBC** 上验证,依赖开发板原厂 U-Boot/OpenSBI 和其动态选择的 +Device Tree。 + +默认配置使用 MMU 并启动 4 个 CPU,从 S-mode 运行 RT-Thread。早期控制台使用 +SBI,正常串口为 `ttyS0`,参数为 115200 8N1。 + +## 2. 支持情况 + +| 功能 | 状态 | 说明 | +| --- | --- | --- | +| RISC-V MMU / SMP | 支持 | 默认启动 4 个 CPU | +| UART / early console | 支持 | SBI early console,8250/PXA UART | +| Clock / reset / power domain | 支持 | K1 CCU、reset 和 PM domain | +| I2C / SPI / QSPI / PWM | 支持 | 包含 PMIC 子设备 | +| SD / eMMC | 支持 | SDHCI,eMMC HS400 | +| RTC / ADC / power key | 支持 | SpacemiT PMIC | +| PCIe / NVMe | 支持 | DesignWare PCIe host | +| Ethernet / PTP | 支持 | K1X EMAC;需启用 `RT_USING_ETHERNET` 和 `RT_ETHERNET_K1X_EMAC` | +| HDMI framebuffer | 支持 | 冷启动建立 HDMI 显示链路 | +| JPU / V2D | 支持 | JPEG 解码和 2D 加速 | +| HDMI / ES8326 audio | 支持 | 48 kHz、双声道、16-bit PCM | +| DVFS / thermal | 支持 | CPUfreq、OPP 和 4 路温度区 | +| AES / hardware RNG / eFuse | 支持 | 包含 SoC ID 和序列号 | +| MIPI DSI / camera / USB | 未移植 | 当前 BSP 不包含这些功能 | + +## 3. 构建环境 + +### 3.1 依赖 + +建议使用 64 位 Linux 主机。Ubuntu/Debian 可安装: + +```shell +sudo apt install scons python3 python3-pip +pip3 install kconfiglib +``` + +### 3.2 工具链 + +可从以下地址获取 RISC-V64 Linux musl GCC 工具链: + +- SpacemiT 官方工具链归档: +- RT-Thread RISC-V64 musl 工具链: + +以解压到 `/opt/riscv64-linux-musleabi_for_x86_64-pc-linux-gnu` 为例: + +```shell +export RTT_CC=gcc +export RTT_EXEC_PATH=/opt/riscv64-linux-musleabi_for_x86_64-pc-linux-gnu/bin +export RTT_CC_PREFIX=riscv64-unknown-linux-musl- +``` + +可使用下列命令检查工具链: + +```shell +${RTT_EXEC_PATH}/${RTT_CC_PREFIX}gcc --version +``` + +## 4. 编译 + +进入 BSP 目录: + +```shell +cd bsp/spacemit/k1 +``` + +需要调整功能时先运行: + +```shell +scons --menuconfig +``` + +编译: + +```shell +scons -j$(nproc) +``` + +编译成功后会生成: + +| 文件 | 用途 | +| --- | --- | +| `rtthread.elf` | 带调试信息的 ELF 文件 | +| `rtthread.bin` | U-Boot 加载的内核镜像 | +| `rtthread.map` | 链接 map | + +清理构建产物: + +```shell +scons -c +``` + +## 5. Banana Pi BPI-F3 启动 + +> 本节命令仅适用于 Banana Pi BPI-F3 原厂 U-Boot 环境。其他 K1 开发板的分区、 +> Device Tree 和 U-Boot 环境变量可能不同。 + +### 5.1 准备镜像 + +将 `rtthread.bin` 放到 BPI-F3 启动文件系统根目录,即与 Linux `Image` 和 +`k1-x_*.dtb` 相同的目录。U-Boot 的 `loadknl` 命令会从当前启动文件系统加载 +`knl_name` 指定的文件。 + +### 5.2 配置 U-Boot + +在 U-Boot 控制台执行以下命令: + +```shell +setenv rtt_bootargs 'earlycon=sbi console=ttyS0,115200 cma=32M coherent_pool=8M root=sd0p4 rootfstype=elm rootwait rw' +setenv boot_rtt 'setenv knl_name rtthread.bin; setenv bootargs ${rtt_bootargs}; run detect_dtb; run loadknl; run loaddtb; setenv ramdisk_combo -; run start_kernel' +saveenv +``` + +`saveenv` 只需执行一次。之后可使用以下命令启动 RT-Thread: + +```shell +run boot_rtt +``` + +主要 bootargs 说明: + +- `earlycon=sbi`:在正常 UART 驱动就绪前使用 SBI 输出。 +- `cma=32M coherent_pool=8M`:为 framebuffer、JPU、V2D、NVMe 和其他 DMA 设备预留内存。 +- `root=sd0p4 rootfstype=elm`:将 RT-Thread 设备 `sd0p4` 上的 FAT 文件系统作为根文件系统。 + +如果存储设备的枚举顺序或分区布局不同,需要相应修改 `root=`。原厂 U-Boot +必须存在 `detect_dtb`、`loadknl`、`loaddtb` 和 `start_kernel` 这几个环境命令。 + +### 5.3 启动输出 + +启动成功后串口将显示: + +```text + \ | / +- RT - Thread Operating System + / | \ + ... +msh /> +``` + +## 6. 常用验证命令 + +```shell +list_device +list_irq +list_blk +list_thermal +list_dvfs +dvfs dump cpufreq0 +core_mark +adc probe adc0 +adc read 0 +date +jpu_show /path/to/image.jpg fb0 +v2d_test fb0 +audio_test snd-hdmi 2 +ptp_test +``` + +`jpu_show` 仅从文件系统读取 baseline JPEG,BSP 不内置测试图片。 + +使用网卡前请先在 `menuconfig` 中启用 Ethernet 和 K1X EMAC,然后根据实际端口 +`e0` 或 `e1` 配置地址: + +```shell +ifconfig e1 192.168.10.2 192.168.10.1 255.255.255.0 +ping 192.168.10.1 e1 +``` + +## 7. 注意事项 + +- Device Tree 由 BPI-F3 U-Boot 的 `detect_dtb` 选择,不要使用与开发板不匹配的 DTB。 +- HDMI 显示依赖 `cma` 和 `coherent_pool`;内存过小时 framebuffer 初始化会失败。 +- HDMI ADMA 依赖嵌入镜像的 K1 RCPU `esos.elf` 和 Device Tree 中的 reserved-memory。 +- MIPI 显示未验证,当前显示驱动仅面向 HDMI。 + diff --git a/bsp/spacemit/k1/README_en.md b/bsp/spacemit/k1/README_en.md new file mode 100644 index 000000000000..b1ddcf7650be --- /dev/null +++ b/bsp/spacemit/k1/README_en.md @@ -0,0 +1,193 @@ +**English** | [中文](README.md) + +# SpacemiT K1 BSP + +## 1. Introduction + +This BSP ports the RT-Thread standard edition to the SpacemiT K1 64-bit +RISC-V SoC. The boot procedure is currently validated only on the +**Banana Pi BPI-F3 SBC**. It relies on the vendor U-Boot/OpenSBI firmware and +the Device Tree selected by U-Boot. + +The default configuration enables the MMU and starts four CPUs. RT-Thread +runs in S-mode. The early console uses SBI, while the normal console is +`ttyS0` at 115200 baud, 8 data bits, no parity, and 1 stop bit. + +## 2. Supported Features + +| Feature | Status | Notes | +| --- | --- | --- | +| RISC-V MMU / SMP | Supported | Four CPUs are enabled by default | +| UART / early console | Supported | SBI early console and 8250/PXA UART | +| Clock / reset / power domain | Supported | K1 CCU, reset, and PM domain | +| I2C / SPI / QSPI / PWM | Supported | Includes PMIC child devices | +| SD / eMMC | Supported | SDHCI and eMMC HS400 | +| RTC / ADC / power key | Supported | SpacemiT PMIC | +| PCIe / NVMe | Supported | DesignWare PCIe host | +| Ethernet / PTP | Supported | Enable `RT_USING_ETHERNET` and `RT_ETHERNET_K1X_EMAC` | +| HDMI framebuffer | Supported | Initializes the HDMI display path from a cold boot | +| JPU / V2D | Supported | JPEG decoding and 2D acceleration | +| HDMI / ES8326 audio | Supported | 48 kHz, stereo, 16-bit PCM | +| DVFS / thermal | Supported | CPUfreq, OPP, and four thermal zones | +| AES / hardware RNG / eFuse | Supported | Includes SoC ID and serial number | +| MIPI DSI / camera / USB | Not ported | These functions are not included in this BSP | + +## 3. Build Environment + +### 3.1 Dependencies + +A 64-bit Linux host is recommended. On Ubuntu or Debian, install: + +```shell +sudo apt install scons python3 python3-pip +pip3 install kconfiglib +``` + +### 3.2 Toolchain + +A RISC-V64 Linux musl GCC toolchain can be obtained from: + +- SpacemiT toolchain archive: +- RT-Thread RISC-V64 musl toolchain: + +The following example assumes that the toolchain is extracted to +`/opt/riscv64-linux-musleabi_for_x86_64-pc-linux-gnu`: + +```shell +export RTT_CC=gcc +export RTT_EXEC_PATH=/opt/riscv64-linux-musleabi_for_x86_64-pc-linux-gnu/bin +export RTT_CC_PREFIX=riscv64-unknown-linux-musl- +``` + +Verify the toolchain with: + +```shell +${RTT_EXEC_PATH}/${RTT_CC_PREFIX}gcc --version +``` + +## 4. Build + +Enter the BSP directory: + +```shell +cd bsp/spacemit/k1 +``` + +To change the configuration, run: + +```shell +scons --menuconfig +``` + +Build the BSP: + +```shell +scons -j$(nproc) +``` + +A successful build generates: + +| File | Description | +| --- | --- | +| `rtthread.elf` | ELF image with debug information | +| `rtthread.bin` | Kernel image loaded by U-Boot | +| `rtthread.map` | Linker map | + +Clean the build output with: + +```shell +scons -c +``` + +## 5. Boot on Banana Pi BPI-F3 + +> The commands in this section apply only to the vendor U-Boot environment +> on the Banana Pi BPI-F3. Other K1 boards may use different partitions, +> Device Trees, and U-Boot variables. + +### 5.1 Install the Image + +Place `rtthread.bin` in the root of the BPI-F3 boot filesystem, next to the +Linux `Image` file and the `k1-x_*.dtb` files. The U-Boot `loadknl` command +loads the file specified by `knl_name` from the active boot filesystem. + +### 5.2 Configure U-Boot + +Run the following commands from the U-Boot console: + +```shell +setenv rtt_bootargs 'earlycon=sbi console=ttyS0,115200 cma=32M coherent_pool=8M root=sd0p4 rootfstype=elm rootwait rw' +setenv boot_rtt 'setenv knl_name rtthread.bin; setenv bootargs ${rtt_bootargs}; run detect_dtb; run loadknl; run loaddtb; setenv ramdisk_combo -; run start_kernel' +saveenv +``` + +`saveenv` is only required once. Boot RT-Thread with: + +```shell +run boot_rtt +``` + +Important boot arguments: + +- `earlycon=sbi` provides output before the normal UART driver is ready. +- `cma=32M coherent_pool=8M` reserves memory for the framebuffer, JPU, V2D, + NVMe, and other DMA devices. +- `root=sd0p4 rootfstype=elm` mounts the FAT filesystem on the RT-Thread + `sd0p4` device as the root filesystem. + +Change `root=` if the storage enumeration order or partition layout differs. +The vendor U-Boot environment must provide the `detect_dtb`, `loadknl`, +`loaddtb`, and `start_kernel` commands. + +### 5.3 Expected Output + +After a successful boot, the serial console displays: + +```text + \ | / +- RT - Thread Operating System + / | \ + ... +msh /> +``` + +## 6. Validation Commands + +```shell +list_device +list_irq +list_blk +list_thermal +list_dvfs +dvfs dump cpufreq0 +core_mark +adc probe adc0 +adc read 0 +date +jpu_show /path/to/image.jpg fb0 +v2d_test fb0 +audio_test snd-hdmi 2 +ptp_test +``` + +`jpu_show` reads a baseline JPEG from the filesystem. No test image is +embedded in the BSP. + +Before using Ethernet, enable Ethernet and the K1X EMAC in `menuconfig`. +Then configure the actual interface, `e0` or `e1`, for example: + +```shell +ifconfig e1 192.168.10.2 192.168.10.1 255.255.255.0 +ping 192.168.10.1 e1 +``` + +## 7. Notes + +- The Device Tree is selected by the BPI-F3 U-Boot `detect_dtb` command. Do + not use a DTB for a different board. +- HDMI display requires the `cma` and `coherent_pool` reservations. The + framebuffer may fail to initialize if either pool is too small. +- HDMI ADMA requires the embedded K1 RCPU `esos.elf` firmware and the + reserved-memory regions in the Device Tree. +- MIPI display is not validated. The current display driver targets HDMI. + diff --git a/bsp/spacemit/k1/SConscript b/bsp/spacemit/k1/SConscript new file mode 100644 index 000000000000..40e1864cf613 --- /dev/null +++ b/bsp/spacemit/k1/SConscript @@ -0,0 +1,16 @@ +# for module compiling +import os +from building import * + +cwd = GetCurrentDir() +objs = [] +list = os.listdir(cwd) + +for d in list: + path = os.path.join(cwd, d) + if os.path.isfile(os.path.join(path, 'SConscript')): + objs = objs + SConscript(os.path.join(d, 'SConscript')) + +objs = objs + SConscript(cwd + '/../dm/SConscript', variant_dir = 'dm', duplicate = 0) + +Return('objs') diff --git a/bsp/spacemit/k1/SConstruct b/bsp/spacemit/k1/SConstruct new file mode 100644 index 000000000000..cf25bd5ecc32 --- /dev/null +++ b/bsp/spacemit/k1/SConstruct @@ -0,0 +1,29 @@ +import os +import sys +import rtconfig + +from rtconfig import RTT_ROOT + +sys.path = sys.path + [os.path.join(RTT_ROOT, 'tools')] +from building import * + +TARGET = 'rtthread.' + rtconfig.TARGET_EXT + +DefaultEnvironment(tools=[]) +env = Environment(tools = ['mingw'], + AS = rtconfig.AS, ASFLAGS = rtconfig.AFLAGS, + CC = rtconfig.CC, CCFLAGS = rtconfig.CFLAGS, + CXX = rtconfig.CXX, CXXFLAGS = rtconfig.CXXFLAGS, + AR = rtconfig.AR, ARFLAGS = '-rc', + LINK = rtconfig.LINK, LINKFLAGS = rtconfig.LFLAGS) +env.PrependENVPath('PATH', rtconfig.EXEC_PATH) +env['ASCOM'] = env['ASPPCOM'] + +Export('RTT_ROOT') +Export('rtconfig') + +# prepare building environment +objs = PrepareBuilding(env, RTT_ROOT, has_libcpu = False) + +# make a building +DoBuilding(TARGET, objs) diff --git a/bsp/spacemit/k1/applications/SConscript b/bsp/spacemit/k1/applications/SConscript new file mode 100644 index 000000000000..c0653a14cca6 --- /dev/null +++ b/bsp/spacemit/k1/applications/SConscript @@ -0,0 +1,9 @@ +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') + Glob('*.cpp') + Glob('*.S') +CPPPATH = [cwd] + +group = DefineGroup('Applications', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/k1/applications/audio.c b/bsp/spacemit/k1/applications/audio.c new file mode 100644 index 000000000000..a92847cc6abb --- /dev/null +++ b/bsp/spacemit/k1/applications/audio.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include + +#if defined(RT_USING_AUDIO) && defined(RT_AUDIO_SPACEMIT) && defined(RT_USING_FINSH) +#include +#include + +#define AUDIO_TEST_RATE 48000U +#define AUDIO_TEST_CHANNELS 2U +#define AUDIO_TEST_BITS 16U +#define AUDIO_TEST_BUFFER_SIZE 4096U +#define AUDIO_TEST_DEFAULT_SECONDS 2U +#define AUDIO_TEST_MAX_SECONDS 30U + +static const rt_int16_t audio_test_sine[] = +{ + 0, 2139, 4240, 6269, 8192, 9974, 11585, 12998, + 14189, 15136, 15825, 16244, 16384, 16244, 15825, 15136, + 14189, 12998, 11585, 9974, 8192, 6269, 4240, 2139, + 0, -2139, -4240, -6269, -8192, -9974,-11585,-12998, + -14189,-15136,-15825,-16244,-16384,-16244,-15825,-15136, + -14189,-12998,-11585, -9974, -8192, -6269, -4240, -2139, +}; + +static int audio_test(int argc, char **argv) +{ + int ret = -RT_ERROR; + rt_uint32_t phase = 0; + rt_uint32_t seconds = AUDIO_TEST_DEFAULT_SECONDS; + rt_size_t remaining; + rt_device_t device; + rt_int16_t *buffer; + const char *name = "snd-es8326"; + struct rt_audio_caps caps = { 0 }; + + if (argc > 1) + { + name = argv[1]; + } + if (argc > 2) + { + seconds = strtoul(argv[2], RT_NULL, 0); + if (!seconds || seconds > AUDIO_TEST_MAX_SECONDS) + { + rt_kprintf("seconds must be 1..%u\n", AUDIO_TEST_MAX_SECONDS); + return -RT_EINVAL; + } + } + + device = rt_device_find(name); + if (!device) + { + rt_kprintf("audio device %s not found\n", name); + return -RT_ENOSYS; + } + + buffer = rt_malloc(AUDIO_TEST_BUFFER_SIZE); + if (!buffer) + { + return -RT_ENOMEM; + } + + if ((ret = rt_device_open(device, RT_DEVICE_OFLAG_WRONLY))) + { + rt_kprintf("open %s failed: %s\n", name, rt_strerror(ret)); + goto _free; + } + + caps.main_type = AUDIO_TYPE_OUTPUT; + caps.sub_type = AUDIO_DSP_PARAM; + caps.udata.config.samplerate = AUDIO_TEST_RATE; + caps.udata.config.channels = AUDIO_TEST_CHANNELS; + caps.udata.config.samplebits = AUDIO_TEST_BITS; + if ((ret = rt_device_control(device, AUDIO_CTL_CONFIGURE, &caps))) + { + rt_kprintf("configure %s failed: %s\n", name, rt_strerror(ret)); + goto _close; + } + + caps.main_type = AUDIO_TYPE_MIXER; + caps.sub_type = AUDIO_MIXER_VOLUME; + caps.udata.value = 65; + rt_device_control(device, AUDIO_CTL_CONFIGURE, &caps); + + remaining = (rt_size_t)seconds * AUDIO_TEST_RATE * + AUDIO_TEST_CHANNELS * sizeof(rt_int16_t); + rt_kprintf("playing 1 kHz tone on %s for %u second(s)\n", name, seconds); + + while (remaining) + { + rt_size_t size = rt_min_t(rt_size_t, remaining, AUDIO_TEST_BUFFER_SIZE); + rt_size_t samples = size / sizeof(*buffer); + + for (rt_size_t i = 0; i < samples; i += 2) + { + rt_int16_t sample = audio_test_sine[phase]; + + buffer[i] = sample; + buffer[i + 1] = sample; + phase = (phase + 1) % RT_ARRAY_SIZE(audio_test_sine); + } + + if (rt_device_write(device, 0, buffer, size) != size) + { + rt_kprintf("write %s failed\n", name); + ret = -RT_EIO; + goto _close; + } + remaining -= size; + } + + ret = RT_EOK; + rt_kprintf("audio_test: queued playback data, closing device\n"); + +_close: + rt_device_close(device); + rt_kprintf("audio_test: device closed\n"); +_free: + rt_free(buffer); + return ret; +} +MSH_CMD_EXPORT(audio_test, play a 1 kHz tone: audio_test [device] [seconds]); +#endif /* RT_USING_AUDIO && RT_AUDIO_SPACEMIT && RT_USING_FINSH */ diff --git a/bsp/spacemit/k1/applications/jpu.c b/bsp/spacemit/k1/applications/jpu.c new file mode 100644 index 000000000000..52d983c855fb --- /dev/null +++ b/bsp/spacemit/k1/applications/jpu.c @@ -0,0 +1,776 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include + +#include + +#if defined(RT_USING_FINSH) && defined(RT_USING_DFS) && defined(RT_USING_GRAPHIC) && defined(RT_SOC_CHIP_MEDIA_JPU) +#include +#include +#include + +#define JPU_ALIGN(value, align) (((value) + (align) - 1) & ~((align) - 1)) +#define JPU_FILE_IO_CHUNK 512U + +struct jpu_huffman +{ + rt_uint8_t bits[JPU_HUFF_BITS_NUM]; + rt_uint8_t values[JPU_HUFF_VALUES_NUM]; + rt_uint16_t count; +}; + +struct jpu_jpeg +{ + rt_uint8_t *data; + rt_size_t size; + rt_uint16_t quant[4][JPU_QUANT_VALUES_NUM]; + struct jpu_huffman huff[JPU_HUFF_TABLE_NUM]; + rt_uint8_t component_id[3]; + rt_uint8_t h[3]; + rt_uint8_t v[3]; + rt_uint8_t qsel[3]; + rt_uint8_t dcsel[3]; + rt_uint8_t acsel[3]; + rt_uint8_t components; + rt_uint8_t format; + rt_uint16_t width; + rt_uint16_t height; + rt_uint16_t aligned_width; + rt_uint16_t aligned_height; + rt_uint16_t restart_interval; + rt_uint16_t y_stride; + rt_uint16_t c_stride; + rt_uint16_t c_height; + rt_size_t entropy_offset; +}; + +static rt_uint16_t jpu_get_be16(const rt_uint8_t *p) +{ + return ((rt_uint16_t)p[0] << 8) | p[1]; +} + +static rt_err_t jpu_read_stream(int fd, void *destination, rt_size_t size) +{ + rt_uint8_t *buffer; + rt_size_t offset = 0; + rt_size_t buffer_size = rt_min(size, (rt_size_t)JPU_FILE_IO_CHUNK); + rt_err_t err = RT_EOK; + + buffer = rt_malloc(buffer_size); + if (!buffer) + { + return -RT_ENOMEM; + } + + while (offset < size) + { + rt_size_t requested = rt_min(size - offset, buffer_size); + ssize_t received = read(fd, buffer, requested); + + if (received <= 0) + { + err = -RT_EIO; + break; + } + + rt_memcpy((rt_uint8_t *)destination + offset, buffer, received); + offset += received; + } + + rt_free(buffer); + return err; +} + +static rt_err_t jpu_parse_dqt(struct jpu_jpeg *jpg, const rt_uint8_t *p, + rt_size_t length) +{ + while (length) + { + rt_uint8_t precision, table; + int i; + + precision = p[0] >> 4; + table = p[0] & 0xf; + ++p; + --length; + if (precision > 1 || table > 3 || + length < (rt_size_t)(JPU_QUANT_VALUES_NUM << precision)) + { + return -RT_EINVAL; + } + + for (i = 0; i < JPU_QUANT_VALUES_NUM; ++i) + { + jpg->quant[table][i] = precision ? jpu_get_be16(p + i * 2) : p[i]; + } + + p += JPU_QUANT_VALUES_NUM << precision; + length -= JPU_QUANT_VALUES_NUM << precision; + } + + return RT_EOK; +} + +static rt_err_t jpu_parse_dht(struct jpu_jpeg *jpg, const rt_uint8_t *p, + rt_size_t length) +{ + while (length) + { + struct jpu_huffman *huff; + rt_uint8_t type, id; + rt_uint16_t count = 0; + int i; + + if (length < 17) + { + return -RT_EINVAL; + } + + type = p[0] >> 4; + id = p[0] & 0xf; + ++p; + --length; + if (type > 1 || id > 1) + { + return -RT_ENOSYS; + } + + huff = &jpg->huff[id * 2 + type]; + for (i = 0; i < JPU_HUFF_BITS_NUM; ++i) + { + count += huff->bits[i] = p[i]; + } + p += JPU_HUFF_BITS_NUM; + length -= JPU_HUFF_BITS_NUM; + + if (count > (type ? JPU_HUFF_VALUES_NUM : 12) || length < count) + { + return -RT_EINVAL; + } + + rt_memcpy(huff->values, p, count); + huff->count = count; + p += count; + length -= count; + } + + return RT_EOK; +} + +static rt_err_t jpu_parse_sof(struct jpu_jpeg *jpg, const rt_uint8_t *p, + rt_size_t length) +{ + rt_uint8_t sample; + int i; + + if (length < 6 || p[0] != 8 || (p[5] != 1 && p[5] != 3) || + length != 6U + p[5] * 3U) + { + return -RT_ENOSYS; + } + + jpg->height = jpu_get_be16(p + 1); + jpg->width = jpu_get_be16(p + 3); + jpg->components = p[5]; + if (!jpg->width || !jpg->height) + { + return -RT_EINVAL; + } + + for (i = 0; i < jpg->components; ++i) + { + jpg->component_id[i] = p[6 + i * 3]; + jpg->h[i] = p[7 + i * 3] >> 4; + jpg->v[i] = p[7 + i * 3] & 0xf; + jpg->qsel[i] = p[8 + i * 3]; + if (!jpg->h[i] || !jpg->v[i] || jpg->qsel[i] > 3) + { + return -RT_EINVAL; + } + } + + if (jpg->components == 1) + { + jpg->format = JPU_FORMAT_400; + } + else + { + if (jpg->h[1] != 1 || jpg->v[1] != 1 || + jpg->h[2] != 1 || jpg->v[2] != 1) + { + return -RT_ENOSYS; + } + + sample = (jpg->h[0] << 2) | jpg->v[0]; + switch (sample) + { + case 0x0a: + jpg->format = JPU_FORMAT_420; + break; + case 0x09: + jpg->format = JPU_FORMAT_422; + break; + case 0x06: + jpg->format = JPU_FORMAT_440; + break; + case 0x05: + jpg->format = JPU_FORMAT_444; + break; + default: + return -RT_ENOSYS; + } + } + + return RT_EOK; +} + +static rt_err_t jpu_parse_sos(struct jpu_jpeg *jpg, const rt_uint8_t *p, + rt_size_t length) +{ + int i, component; + + if (length < 4 || p[0] != jpg->components || + length != 4U + p[0] * 2U) + { + return -RT_ENOSYS; + } + + for (i = 0; i < p[0]; ++i) + { + for (component = 0; component < jpg->components; ++component) + { + if (jpg->component_id[component] == p[1 + i * 2]) + { + break; + } + } + + if (component == jpg->components || + (p[2 + i * 2] >> 4) > 1 || (p[2 + i * 2] & 0xf) > 1) + { + return -RT_ENOSYS; + } + + jpg->dcsel[component] = p[2 + i * 2] >> 4; + jpg->acsel[component] = p[2 + i * 2] & 0xf; + } + + if (p[length - 3] != 0 || p[length - 2] != 63 || p[length - 1] != 0) + { + return -RT_ENOSYS; + } + + return RT_EOK; +} + +static rt_err_t jpu_validate_tables(struct jpu_jpeg *jpg) +{ + int i; + + for (i = 0; i < jpg->components; ++i) + { + if (!jpg->huff[jpg->dcsel[i] * 2].count || + !jpg->huff[jpg->acsel[i] * 2 + 1].count || + !jpg->quant[jpg->qsel[i]][0]) + { + return -RT_EINVAL; + } + } + + return RT_EOK; +} + +static rt_err_t jpu_parse(struct jpu_jpeg *jpg) +{ + rt_size_t pos = 2; + rt_bool_t have_sof = RT_FALSE; + + if (jpg->size < 4 || jpu_get_be16(jpg->data) != 0xffd8) + { + return -RT_EINVAL; + } + + while (pos + 1 < jpg->size) + { + rt_uint8_t marker; + rt_uint16_t section_length; + const rt_uint8_t *section; + rt_err_t err = RT_EOK; + + while (pos < jpg->size && jpg->data[pos] == 0xff) + { + ++pos; + } + if (pos >= jpg->size) + { + break; + } + + marker = jpg->data[pos++]; + if (marker == 0xd9) + { + break; + } + if (marker == 0xd8 || (marker >= 0xd0 && marker <= 0xd7)) + { + continue; + } + if (pos + 2 > jpg->size) + { + return -RT_EINVAL; + } + + section_length = jpu_get_be16(jpg->data + pos); + if (section_length < 2 || pos + section_length > jpg->size) + { + return -RT_EINVAL; + } + section = jpg->data + pos + 2; + + switch (marker) + { + case 0xc0: + err = jpu_parse_sof(jpg, section, section_length - 2); + have_sof = err == RT_EOK; + break; + case 0xc4: + err = jpu_parse_dht(jpg, section, section_length - 2); + break; + case 0xdb: + err = jpu_parse_dqt(jpg, section, section_length - 2); + break; + case 0xdd: + if (section_length != 4) + { + err = -RT_EINVAL; + } + else + { + jpg->restart_interval = jpu_get_be16(section); + } + break; + case 0xda: + if (!have_sof) + { + return -RT_EINVAL; + } + if ((err = jpu_parse_sos(jpg, section, section_length - 2)) != RT_EOK) + { + return err; + } + jpg->entropy_offset = pos + section_length; + return jpu_validate_tables(jpg); + default: + if (marker >= 0xc1 && marker <= 0xcf && + marker != 0xc4 && marker != 0xc8 && marker != 0xcc) + { + return -RT_ENOSYS; + } + break; + } + + if (err != RT_EOK) + { + return err; + } + pos += section_length; + } + + return -RT_EINVAL; +} + +static void jpu_fill_tables(struct jpu_dec_tables *tables, + const struct jpu_jpeg *jpg) +{ + const struct jpu_huffman *fallback_dc = RT_NULL; + const struct jpu_huffman *fallback_ac = RT_NULL; + int table, component; + + for (table = 0; table < JPU_HUFF_TABLE_NUM; ++table) + { + if (jpg->huff[table].count) + { + if (table & 1) + { + fallback_ac = &jpg->huff[table]; + } + else + { + fallback_dc = &jpg->huff[table]; + } + } + } + + for (table = 0; table < JPU_HUFF_TABLE_NUM; ++table) + { + const struct jpu_huffman *huff = &jpg->huff[table]; + + if (!huff->count) + { + huff = (table & 1) ? fallback_ac : fallback_dc; + } + rt_memcpy(tables->huff_bits[table], huff->bits, + sizeof(tables->huff_bits[table])); + rt_memcpy(tables->huff_values[table], huff->values, + sizeof(tables->huff_values[table])); + } + + for (component = 0; component < JPU_QUANT_COMPONENT_NUM; ++component) + { + int source = component < jpg->components ? component : 0; + + rt_memcpy(tables->quant[component], jpg->quant[jpg->qsel[source]], + sizeof(tables->quant[component])); + } +} + +static void jpu_fill_request(struct jpu_decode_request *req, + const struct jpu_jpeg *jpg) +{ + req->frame.width = jpg->width; + req->frame.height = jpg->height; + req->frame.format = jpg->format; + req->entropy_offset = jpg->entropy_offset; + req->restart_interval = jpg->restart_interval; + req->components = jpg->components; + rt_memcpy(req->dc_selector, jpg->dcsel, sizeof(req->dc_selector)); + rt_memcpy(req->ac_selector, jpg->acsel, sizeof(req->ac_selector)); + jpu_fill_tables(&req->tables, jpg); +} + +static rt_uint8_t jpu_clip(int value) +{ + if (value < 0) + { + return 0; + } + if (value > 255) + { + return 255; + } + return value; +} + +static rt_err_t jpu_store_pixel(rt_uint8_t format, rt_uint8_t *dst, + rt_uint8_t r, rt_uint8_t g, rt_uint8_t b) +{ + switch (format) + { + case RTGRAPHIC_PIXEL_FORMAT_RGB565: + *(rt_uint16_t *)dst = (r >> 3) << 11 | (g >> 2) << 5 | (b >> 3); + break; + case RTGRAPHIC_PIXEL_FORMAT_BGR565: + *(rt_uint16_t *)dst = (b >> 3) << 11 | (g >> 2) << 5 | (r >> 3); + break; + case RTGRAPHIC_PIXEL_FORMAT_RGB888: + dst[0] = r; + dst[1] = g; + dst[2] = b; + break; + case RTGRAPHIC_PIXEL_FORMAT_BGR888: + dst[0] = b; + dst[1] = g; + dst[2] = r; + break; + case RTGRAPHIC_PIXEL_FORMAT_ARGB888: + *(rt_uint32_t *)dst = 0xff000000U | (rt_uint32_t)r << 16 | + (rt_uint32_t)g << 8 | b; + break; + case RTGRAPHIC_PIXEL_FORMAT_ABGR888: + *(rt_uint32_t *)dst = 0xff000000U | (rt_uint32_t)b << 16 | + (rt_uint32_t)g << 8 | r; + break; + default: + return -RT_ENOSYS; + } + + return RT_EOK; +} + +static rt_err_t jpu_show_frame(const char *fb_name, const struct jpu_jpeg *jpg, + const rt_uint8_t *frame) +{ + struct rt_device_graphic_info info; + struct rt_graphic_device *graphic; + rt_device_t fb = rt_device_find(fb_name); + rt_bool_t restore_auto_update; + rt_uint8_t *display_buffer; + rt_size_t screen_size; + const rt_uint8_t *y_plane = frame; + const rt_uint8_t *cb_plane = y_plane + jpg->y_stride * jpg->aligned_height; + const rt_uint8_t *cr_plane = cb_plane + jpg->c_stride * jpg->c_height; + int x0, y0, copy_width, copy_height, source_x, source_y; + int bytes_per_pixel, x, y; + rt_err_t err; + + if (!fb) + { + return -RT_ENOSYS; + } + + graphic = rt_container_of(fb, struct rt_graphic_device, parent); + restore_auto_update = graphic->update_timer != RT_NULL; + if ((err = rt_device_open(fb, RT_DEVICE_OFLAG_RDWR)) != RT_EOK) + { + return err; + } + if ((err = rt_device_control(fb, RTGRAPHIC_CTRL_GET_INFO, &info)) != RT_EOK) + { + goto _out; + } + if (!info.framebuffer || !(bytes_per_pixel = info.bits_per_pixel / 8)) + { + err = -RT_EINVAL; + goto _out; + } + screen_size = (rt_size_t)info.pitch * info.height; + if (!screen_size || screen_size > info.smem_len / 2U) + { + rt_kprintf("%s needs a double framebuffer for tear-free display " + "(have %u, need %u bytes)\n", fb_name, + (unsigned int)info.smem_len, + (unsigned int)(screen_size * 2U)); + err = -RT_ENOMEM; + goto _out; + } + display_buffer = (rt_uint8_t *)info.framebuffer + screen_size; + + if ((err = rt_device_control(fb, RTGRAPHIC_CTRL_POWERON, RT_NULL)) != RT_EOK) + { + goto _out; + } + + if (restore_auto_update) + { + rt_graphic_device_update_auto(graphic, 0); + } + + if ((err = rt_device_control(fb, RTGRAPHIC_CTRL_PAN_DISPLAY, + info.framebuffer)) != RT_EOK || + (err = rt_device_control(fb, RTGRAPHIC_CTRL_WAIT_VSYNC, + RT_NULL)) != RT_EOK) + { + goto _restore; + } + + rt_memset(display_buffer, 0, screen_size); + copy_width = rt_min((int)jpg->width, (int)info.width); + copy_height = rt_min((int)jpg->height, (int)info.height); + x0 = (info.width - copy_width) / 2; + y0 = (info.height - copy_height) / 2; + source_x = (jpg->width - copy_width) / 2; + source_y = (jpg->height - copy_height) / 2; + + for (y = 0; y < copy_height; ++y) + { + rt_uint8_t *dst = display_buffer + + (y0 + y) * info.pitch + x0 * bytes_per_pixel; + int sy = source_y + y; + + for (x = 0; x < copy_width; ++x) + { + int sx = source_x + x; + int cx = sx, cy = sy; + int yy, cb = 128, cr = 128; + rt_uint8_t r, g, b; + + if (jpg->format == JPU_FORMAT_420 || jpg->format == JPU_FORMAT_422) + { + cx >>= 1; + } + if (jpg->format == JPU_FORMAT_420 || jpg->format == JPU_FORMAT_440) + { + cy >>= 1; + } + yy = y_plane[sy * jpg->y_stride + sx]; + if (jpg->format != JPU_FORMAT_400) + { + cb = cb_plane[cy * jpg->c_stride + cx]; + cr = cr_plane[cy * jpg->c_stride + cx]; + } + + cb -= 128; + cr -= 128; + r = jpu_clip(yy + ((359 * cr) >> 8)); + g = jpu_clip(yy - ((88 * cb + 183 * cr) >> 8)); + b = jpu_clip(yy + ((454 * cb) >> 8)); + if ((err = jpu_store_pixel(info.pixel_format, + dst + x * bytes_per_pixel, r, g, b)) != RT_EOK) + { + goto _restore; + } + } + } + + if ((err = rt_device_control(fb, RTGRAPHIC_CTRL_PAN_DISPLAY, + display_buffer)) != RT_EOK || + (err = rt_device_control(fb, RTGRAPHIC_CTRL_WAIT_VSYNC, + RT_NULL)) != RT_EOK) + { + goto _restore; + } + +_restore: + if (restore_auto_update) + { + rt_graphic_device_update_auto(graphic, RT_GRAPHIC_UPDATE_MS); + } +_out: + rt_device_close(fb); + return err; +} + +static int jpu_show(int argc, char **argv) +{ + const char *path; + const char *fb_name; + struct jpu_jpeg jpg = { 0 }; + struct jpu_buffer stream = { 0 }; + struct jpu_buffer frame = { 0 }; + struct jpu_decode_request *req = RT_NULL; + rt_device_t jpu = rt_device_find("jpu0"); + off_t file_size; + int fd = -1; + rt_err_t err = -RT_ERROR; + + if (argc < 2 || argc > 3) + { + rt_kprintf("Usage: jpu_show [framebuffer]\n"); + return -RT_EINVAL; + } + + path = argv[1]; + fb_name = argc > 2 ? argv[2] : "fb0"; + + if (!jpu) + { + rt_kprintf("jpu0 not found\n"); + return -RT_ENOSYS; + } + if ((err = rt_device_open(jpu, RT_DEVICE_OFLAG_RDWR)) != RT_EOK) + { + rt_kprintf("open jpu0 failed: %d\n", err); + return err; + } + + fd = open(path, O_RDONLY, 0); + if (fd < 0) + { + rt_kprintf("open %s failed\n", path); + err = -RT_EIO; + goto _out; + } + file_size = lseek(fd, 0, SEEK_END); + if (lseek(fd, 0, SEEK_SET) < 0) + { + err = -RT_EIO; + goto _out; + } + if (file_size <= 0 || file_size > JPU_BUFFER_MAX_SIZE - JPU_STREAM_PADDING) + { + err = -RT_EINVAL; + goto _out; + } + + stream.size = JPU_ALIGN((rt_size_t)file_size + JPU_STREAM_PADDING, 4096); + if ((err = rt_device_control(jpu, JPU_ALLOC_BUFFER, &stream)) != RT_EOK) + { + rt_kprintf("allocate JPU stream buffer failed: %d\n", err); + goto _out; + } + rt_memset(stream.virt_addr, 0xff, stream.size); + if ((err = jpu_read_stream(fd, stream.virt_addr, file_size)) != RT_EOK) + { + rt_kprintf("read %s into JPU stream buffer failed: %d\n", path, err); + goto _out; + } + + jpg.data = stream.virt_addr; + jpg.size = file_size; + if ((err = jpu_parse(&jpg)) != RT_EOK) + { + rt_kprintf("unsupported or invalid baseline JPEG: %d\n", err); + goto _out; + } + + req = rt_calloc(1, sizeof(*req)); + if (!req) + { + err = -RT_ENOMEM; + goto _out; + } + jpu_fill_request(req, &jpg); + if ((err = rt_device_control(jpu, JPU_QUERY_FRAME, &req->frame)) != RT_EOK) + { + rt_kprintf("unsupported JPU output layout: %d\n", err); + goto _out; + } + + jpg.aligned_width = req->frame.aligned_width; + jpg.aligned_height = req->frame.aligned_height; + jpg.y_stride = req->frame.y_stride; + jpg.c_stride = req->frame.c_stride; + jpg.c_height = req->frame.c_height; + + frame.size = JPU_ALIGN(req->frame.size, 4096); + if ((err = rt_device_control(jpu, JPU_ALLOC_BUFFER, &frame)) != RT_EOK) + { + rt_kprintf("allocate JPU frame buffer failed: %d\n", err); + goto _out; + } + rt_memset(frame.virt_addr, 0, frame.size); + + req->stream_phys = stream.phys_addr; + req->frame_phys = frame.phys_addr; + req->stream_size = jpg.size; + req->stream_capacity = stream.size; + req->frame_capacity = frame.size; + + if ((err = rt_device_control(jpu, JPU_DECODE, req)) != RT_EOK) + { + rt_kprintf("JPU decode failed: %d, irq=0x%08x status=0x%08x errmb=0x%08x\n", + err, req->irq_status, req->picture_status, req->error_mcu); + goto _out; + } + + if ((err = jpu_show_frame(fb_name, &jpg, frame.virt_addr)) != RT_EOK) + { + rt_kprintf("display on %s failed: %d\n", fb_name, err); + } + else + { + rt_kprintf("JPU decoded %s (%ux%u) on %s\n", + path, jpg.width, jpg.height, fb_name); + } + +_out: + if (req) + { + rt_free(req); + } + if (frame.virt_addr) + { + rt_device_control(jpu, JPU_FREE_BUFFER, &frame); + } + if (stream.virt_addr) + { + rt_device_control(jpu, JPU_FREE_BUFFER, &stream); + } + if (fd >= 0) + { + close(fd); + } + rt_device_close(jpu); + return err; +} +MSH_CMD_EXPORT(jpu_show, decode a baseline JPEG with K1 JPU and display it); +#endif /* RT_USING_FINSH && RT_USING_DFS && RT_USING_GRAPHIC && RT_SOC_CHIP_MEDIA_JPU */ diff --git a/bsp/spacemit/k1/applications/main.c b/bsp/spacemit/k1/applications/main.c new file mode 100644 index 000000000000..4450b5b4b0ab --- /dev/null +++ b/bsp/spacemit/k1/applications/main.c @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2017-5-30 bernard the first version + */ + +#include + +int main(int argc, char** argv) +{ + rt_kprintf("Hi, this is RT-Thread!!\n"); + + return 0; +} diff --git a/bsp/spacemit/k1/applications/v2d.c b/bsp/spacemit/k1/applications/v2d.c new file mode 100644 index 000000000000..63e5693f20f9 --- /dev/null +++ b/bsp/spacemit/k1/applications/v2d.c @@ -0,0 +1,468 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include + +#include + +#if defined(RT_USING_FINSH) && defined(RT_USING_GRAPHIC) && defined(RT_SOC_SPACEMIT_V2D) +#include +#include + +#define V2D_TEST_WIDTH 320U +#define V2D_TEST_HEIGHT 240U +#define V2D_TEST_STRIDE (V2D_TEST_WIDTH * 4U) +#define V2D_TEST_DEFAULT_FRAMES 240U +#define V2D_TEST_MAX_FRAMES 3600U +#define V2D_TEST_MAX_DEVICES 32U + +static rt_device_t v2d_test_find_device(char *name, rt_size_t name_size) +{ + rt_uint32_t id; + + for (id = 0; id < V2D_TEST_MAX_DEVICES; ++id) + { + rt_device_t device; + + rt_snprintf(name, name_size, "v2d%u", id); + device = rt_device_find(name); + if (device) + { + return device; + } + } + + name[0] = '\0'; + return RT_NULL; +} + +static void v2d_test_set_address(V2D_SURFACE_S *surface, + const V2D_BUFFER_S *buffer) +{ + surface->phyaddr_y_l = (rt_uint32_t)buffer->phys_addr; + surface->phyaddr_y_h = (rt_uint32_t)(buffer->phys_addr >> 32); +} + +static void v2d_test_fill_pattern(rt_uint32_t *pixels) +{ + static const rt_uint32_t colors[] = + { + 0xffff3030U, + 0xffffa020U, + 0xffffff30U, + 0xff30d060U, + 0xff30d8ffU, + 0xff4070ffU, + 0xffb050e0U, + 0xffffffffU, + }; + rt_uint32_t x, y; + + for (y = 0; y < V2D_TEST_HEIGHT; ++y) + { + for (x = 0; x < V2D_TEST_WIDTH; ++x) + { + rt_uint32_t color = colors[x * RT_ARRAY_SIZE(colors) / + V2D_TEST_WIDTH]; + + if (x < 3 || y < 3 || x >= V2D_TEST_WIDTH - 3 || + y >= V2D_TEST_HEIGHT - 3 || x % 40 < 2 || y % 40 < 2) + { + color = 0xff101010U; + } + if (x + y >= V2D_TEST_WIDTH - 2 && + x + y <= V2D_TEST_WIDTH + 2) + { + color = 0xffffffffU; + } + + pixels[y * V2D_TEST_WIDTH + x] = color; + } + } +} + +static rt_err_t v2d_test_get_format(const struct rt_device_graphic_info *info, + V2D_COLOR_FORMAT_E *format) +{ + switch (info->pixel_format) + { + case RTGRAPHIC_PIXEL_FORMAT_ARGB888: + *format = V2D_COLOR_FORMAT_BGRA8888; + break; + case RTGRAPHIC_PIXEL_FORMAT_ABGR888: + *format = V2D_COLOR_FORMAT_RGBA8888; + break; + case RTGRAPHIC_PIXEL_FORMAT_RGB565: + *format = V2D_COLOR_FORMAT_BGR565; + break; + case RTGRAPHIC_PIXEL_FORMAT_BGR565: + *format = V2D_COLOR_FORMAT_RGB565; + break; + default: + return -RT_ENOSYS; + } + + return RT_EOK; +} + +static rt_uint32_t v2d_test_triangle(rt_uint32_t frame, rt_uint32_t period, + rt_uint32_t amplitude) +{ + rt_uint32_t half = period / 2; + rt_uint32_t phase = frame % period; + + if (phase > half) + { + phase = period - phase; + } + + return half ? (rt_uint64_t)amplitude * phase / half : 0; +} + +static rt_uint32_t v2d_test_rgba(rt_uint8_t r, rt_uint8_t g, + rt_uint8_t b, rt_uint8_t a) +{ + return (rt_uint32_t)a << 24 | (rt_uint32_t)b << 16 | + (rt_uint32_t)g << 8 | r; +} + +static void v2d_test_fill_task(V2D_SUBMIT_TASK_S *task, + const V2D_BUFFER_S *source, const V2D_BUFFER_S *destination, + const struct rt_device_graphic_info *info, + V2D_COLOR_FORMAT_E destination_format) +{ + V2D_BLEND_LAYER_CONF_S *blend; + + rt_memset(task, 0, sizeof(*task)); + + v2d_test_set_address(&task->param.layer0, source); + task->param.layer0.w = V2D_TEST_WIDTH; + task->param.layer0.h = V2D_TEST_HEIGHT; + task->param.layer0.stride = V2D_TEST_STRIDE; + task->param.layer0.format = V2D_COLOR_FORMAT_BGRA8888; + task->param.l0_rect.w = V2D_TEST_WIDTH; + task->param.l0_rect.h = V2D_TEST_HEIGHT; + + v2d_test_set_address(&task->param.dst, destination); + task->param.dst.w = info->width; + task->param.dst.h = info->height; + task->param.dst.stride = info->pitch; + task->param.dst.format = destination_format; + task->param.dst_rect.w = info->width; + task->param.dst_rect.h = info->height; + + task->param.blendconf.blend_cmd = V2D_BLENDCMD_ALPHA; + task->param.blendconf.bgcolor.enable = true; + task->param.blendconf.bgcolor.fillcolor.format = + V2D_COLOR_FORMAT_RGBA8888; + task->param.blendconf.bgcolor.fillcolor.colorvalue = 0xff202020U; + + blend = &task->param.blendconf.blendlayer[0]; + blend->blend_alpha_source = V2D_BLENDALPHA_SOURCE_GOLBAL; + blend->blend_pre_alpha_func = V2D_BLEND_PRE_ALPHA_FUNC_DISABLE; + blend->global_alpha = 0xff; + blend->stBlendFactor.srcColorFactor = V2D_BLEND_ONE; + blend->stBlendFactor.dstColorFactor = V2D_BLEND_ZERO; + blend->stBlendFactor.srcAlphaFactor = V2D_BLEND_ONE; + blend->stBlendFactor.dstAlphaFactor = V2D_BLEND_ZERO; + blend->blend_area.w = info->width; + blend->blend_area.h = info->height; + + task->param.layer1.solidcolor.enable = true; + task->param.layer1.solidcolor.fillcolor.format = + V2D_COLOR_FORMAT_RGBA8888; + task->param.layer1.solidcolor.fillcolor.colorvalue = + v2d_test_rgba(255, 255, 255, 255); + + blend = &task->param.blendconf.blendlayer[1]; + blend->blend_alpha_source = V2D_BLENDALPHA_SOURCE_GOLBAL; + blend->blend_pre_alpha_func = V2D_BLEND_PRE_ALPHA_FUNC_DISABLE; + blend->global_alpha = 0xa0; + blend->stBlendFactor.srcColorFactor = V2D_BLEND_SRC_ALPHA; + blend->stBlendFactor.dstColorFactor = V2D_BLEND_ONE_MINUS_SRC_ALPHA; + blend->stBlendFactor.srcAlphaFactor = V2D_BLEND_ONE; + blend->stBlendFactor.dstAlphaFactor = V2D_BLEND_ONE_MINUS_SRC_ALPHA; + blend->blend_area.w = info->width / 5; + blend->blend_area.h = info->height / 5; + + task->param.l0_rt = V2D_ROT_0; + task->param.l1_rt = V2D_ROT_0; + task->param.l0_csc = V2D_CSC_MODE_BUTT; + task->param.l1_csc = V2D_CSC_MODE_BUTT; + task->param.dither = V2D_NO_DITHER; + task->acquireFencefd = -1; + task->completeFencefd = -1; +} + +static void v2d_test_animate_task(V2D_SUBMIT_TASK_S *task, + const struct rt_device_graphic_info *info, rt_uint32_t frame) +{ + static const V2D_ROTATE_ANGLE_E rotations[] = + { + V2D_ROT_0, + V2D_ROT_90, + V2D_ROT_180, + V2D_ROT_270, + V2D_ROT_MIRROR, + V2D_ROT_FLIP, + }; + V2D_BLEND_LAYER_CONF_S *layer0 = + &task->param.blendconf.blendlayer[0]; + V2D_BLEND_LAYER_CONF_S *layer1 = + &task->param.blendconf.blendlayer[1]; + rt_uint32_t min_width, max_width, min_height, max_height; + rt_uint32_t width, height; + rt_uint32_t red, green, blue; + + min_width = rt_min((rt_uint32_t)info->width, + rt_max((rt_uint32_t)96, (rt_uint32_t)info->width / 8)); + max_width = rt_max(min_width, (rt_uint32_t)info->width * 3 / 4); + min_height = rt_min((rt_uint32_t)info->height, + rt_max((rt_uint32_t)72, (rt_uint32_t)info->height / 8)); + max_height = rt_max(min_height, (rt_uint32_t)info->height * 3 / 4); + + width = min_width + v2d_test_triangle(frame, 151, + max_width - min_width); + height = min_height + v2d_test_triangle(frame + 37, 127, + max_height - min_height); + layer0->blend_area.w = width; + layer0->blend_area.h = height; + layer0->blend_area.x = v2d_test_triangle(frame, 137, + info->width - width); + layer0->blend_area.y = v2d_test_triangle(frame + 29, 103, + info->height - height); + task->param.l0_rt = rotations[(frame / 40) % RT_ARRAY_SIZE(rotations)]; + + width = rt_max((rt_uint32_t)32, (rt_uint32_t)info->width / 5); + height = rt_max((rt_uint32_t)32, (rt_uint32_t)info->height / 5); + width = rt_min(width, (rt_uint32_t)info->width); + height = rt_min(height, (rt_uint32_t)info->height); + layer1->blend_area.w = width; + layer1->blend_area.h = height; + layer1->blend_area.x = v2d_test_triangle(frame + 61, 113, + info->width - width); + layer1->blend_area.y = v2d_test_triangle(frame + 17, 89, + info->height - height); + layer1->global_alpha = 80 + v2d_test_triangle(frame + 23, 97, 144); + + red = 20 + v2d_test_triangle(frame, 181, 52); + green = 24 + v2d_test_triangle(frame + 53, 157, 48); + blue = 32 + v2d_test_triangle(frame + 101, 193, 64); + task->param.blendconf.bgcolor.fillcolor.colorvalue = + v2d_test_rgba(red, green, blue, 255); + + red = 96 + v2d_test_triangle(frame + 73, 109, 159); + green = 64 + v2d_test_triangle(frame + 7, 131, 191); + blue = 80 + v2d_test_triangle(frame + 41, 149, 175); + task->param.layer1.solidcolor.fillcolor.colorvalue = + v2d_test_rgba(red, green, blue, 255); +} + +static rt_err_t v2d_test_parse_frames(const char *text, + rt_uint32_t *frames) +{ + char *end; + unsigned long value = strtoul(text, &end, 0); + + if (!text[0] || *end || !value || value > V2D_TEST_MAX_FRAMES) + { + return -RT_EINVAL; + } + + *frames = value; + return RT_EOK; +} + +static int v2d_test(int argc, char **argv) +{ + const char *fb_name = argc > 1 ? argv[1] : "fb0"; + struct rt_device_graphic_info info; + struct rt_graphic_device *graphic; + V2D_BUFFER_S source = { 0 }; + V2D_BUFFER_S destination = { 0 }; + V2D_SUBMIT_TASK_S task; + V2D_COLOR_FORMAT_E destination_format; + rt_device_t v2d, fb; + rt_uint8_t *front_buffer, *back_buffer, *swap_buffer; + char v2d_name[RT_NAME_MAX]; + rt_size_t screen_size; + rt_uint32_t frame_count = V2D_TEST_DEFAULT_FRAMES; + rt_uint32_t frame; + rt_tick_t start_ms, elapsed_ms; + rt_bool_t v2d_opened = RT_FALSE; + rt_bool_t fb_opened = RT_FALSE; + rt_bool_t restore_auto_update = RT_FALSE; + rt_err_t err; + + if (argc > 3 || (argc > 2 && + v2d_test_parse_frames(argv[2], &frame_count) != RT_EOK)) + { + rt_kprintf("Usage: v2d_test [framebuffer] [frames: 1-%u]\n", + V2D_TEST_MAX_FRAMES); + return -RT_EINVAL; + } + + v2d = v2d_test_find_device(v2d_name, sizeof(v2d_name)); + fb = rt_device_find(fb_name); + if (!v2d || !fb) + { + rt_kprintf("V2D device or framebuffer %s not found\n", fb_name); + return -RT_ENOSYS; + } + + if ((err = rt_device_open(v2d, RT_DEVICE_OFLAG_RDWR)) != RT_EOK) + { + rt_kprintf("open %s failed: %d\n", v2d_name, err); + return err; + } + v2d_opened = RT_TRUE; + + if ((err = rt_device_open(fb, RT_DEVICE_OFLAG_RDWR)) != RT_EOK) + { + rt_kprintf("open %s failed: %d\n", fb_name, err); + goto _out; + } + fb_opened = RT_TRUE; + + if ((err = rt_device_control(fb, RTGRAPHIC_CTRL_GET_INFO, &info)) != + RT_EOK) + { + goto _out; + } + screen_size = (rt_size_t)info.pitch * info.height; + if (!info.framebuffer || !info.width || !info.height || !info.pitch || + screen_size > info.smem_len || screen_size > V2D_BUFFER_MAX_SIZE || + (err = v2d_test_get_format(&info, &destination_format)) != RT_EOK) + { + err = -RT_EINVAL; + rt_kprintf("unsupported framebuffer layout: %ux%u pitch=%u fmt=%u\n", + info.width, info.height, info.pitch, info.pixel_format); + goto _out; + } + if (screen_size > info.smem_len / 2U) + { + err = -RT_ENOMEM; + rt_kprintf("%s needs a double framebuffer for tear-free animation " + "(have %u, need %u bytes)\n", fb_name, + (unsigned int)info.smem_len, + (unsigned int)(screen_size * 2U)); + goto _out; + } + front_buffer = info.framebuffer; + back_buffer = front_buffer + screen_size; + + source.size = V2D_TEST_STRIDE * V2D_TEST_HEIGHT; + if ((err = rt_device_control(v2d, V2D_ALLOC_BUFFER, &source)) != RT_EOK) + { + rt_kprintf("allocate V2D source failed: %d\n", err); + goto _out; + } + destination.size = screen_size; + if ((err = rt_device_control(v2d, V2D_ALLOC_BUFFER, &destination)) != + RT_EOK) + { + rt_kprintf("allocate V2D destination failed: %d\n", err); + goto _out; + } + + v2d_test_fill_pattern(source.virt_addr); + rt_memset(destination.virt_addr, 0, destination.size); + v2d_test_fill_task(&task, &source, &destination, &info, + destination_format); + + if ((err = rt_device_control(fb, RTGRAPHIC_CTRL_POWERON, RT_NULL)) != + RT_EOK) + { + goto _out; + } + graphic = rt_container_of(fb, struct rt_graphic_device, parent); + restore_auto_update = graphic->update_timer != RT_NULL; + if (restore_auto_update) + { + rt_graphic_device_update_auto(graphic, 0); + } + + if ((err = rt_device_control(fb, RTGRAPHIC_CTRL_PAN_DISPLAY, + front_buffer)) != RT_EOK || + (err = rt_device_control(fb, RTGRAPHIC_CTRL_WAIT_VSYNC, + RT_NULL)) != RT_EOK) + { + rt_kprintf("framebuffer page-flip setup failed: %d\n", err); + goto _out; + } + + rt_kprintf("V2D animation: %ux%u BGRA8888 -> %ux%u format %u, %u frames\n", + V2D_TEST_WIDTH, V2D_TEST_HEIGHT, info.width, info.height, + info.pixel_format, frame_count); + start_ms = rt_tick_get_millisecond(); + + for (frame = 0; frame < frame_count; ++frame) + { + v2d_test_animate_task(&task, &info, frame * 2U); + if ((err = rt_device_control(v2d, V2D_SUBMIT, &task)) != RT_EOK) + { + rt_kprintf("V2D submit failed at frame %u: %d\n", frame, err); + goto _out; + } + + rt_memcpy(back_buffer, destination.virt_addr, screen_size); + if ((err = rt_device_control(fb, RTGRAPHIC_CTRL_PAN_DISPLAY, + back_buffer)) != RT_EOK || + (err = rt_device_control(fb, RTGRAPHIC_CTRL_WAIT_VSYNC, + RT_NULL)) != RT_EOK) + { + rt_kprintf("framebuffer update failed at frame %u: %d\n", + frame, err); + goto _out; + } + + swap_buffer = front_buffer; + front_buffer = back_buffer; + back_buffer = swap_buffer; + } + + elapsed_ms = rt_tick_get_millisecond() - start_ms; + if (!elapsed_ms) + { + elapsed_ms = 1; + } + rt_kprintf("V2D animation done on %s: %u frames in %u ms, %u.%u fps\n", + fb_name, frame_count, (unsigned int)elapsed_ms, + (unsigned int)((rt_uint64_t)frame_count * 1000 / elapsed_ms), + (unsigned int)(((rt_uint64_t)frame_count * 10000 / elapsed_ms) % 10)); + err = RT_EOK; + +_out: + if (restore_auto_update) + { + rt_graphic_device_update_auto(graphic, RT_GRAPHIC_UPDATE_MS); + } + if (destination.virt_addr) + { + rt_device_control(v2d, V2D_FREE_BUFFER, &destination); + } + if (source.virt_addr) + { + rt_device_control(v2d, V2D_FREE_BUFFER, &source); + } + if (fb_opened) + { + rt_device_close(fb); + } + if (v2d_opened) + { + rt_device_close(v2d); + } + + return err; +} +MSH_CMD_EXPORT(v2d_test, run the K1 V2D animation and framebuffer test); +#endif /* RT_USING_FINSH && RT_USING_GRAPHIC && RT_SOC_SPACEMIT_V2D */ diff --git a/bsp/spacemit/k1/drivers/README.md b/bsp/spacemit/k1/drivers/README.md new file mode 100644 index 000000000000..1cb0cab83c43 --- /dev/null +++ b/bsp/spacemit/k1/drivers/README.md @@ -0,0 +1,13 @@ +# K1 Firmware + +`esos.elf` is the SpacemiT K1 RCPU firmware used by the HDMI ADMA service. +It was obtained from `/lib/firmware/esos.elf` in the vendor Bianbu Linux +image and is embedded into `rtthread.bin` by `firmware.S`. + +Validated SHA-256: + +```text +d643349c9705b665b7af438cf8fcd46c1af2ef743f4249155b62ead3efbd8f9f esos.elf +``` + +Confirm the vendor firmware redistribution terms before upstream submission. diff --git a/bsp/spacemit/k1/drivers/SConscript b/bsp/spacemit/k1/drivers/SConscript new file mode 100644 index 000000000000..0022841c24da --- /dev/null +++ b/bsp/spacemit/k1/drivers/SConscript @@ -0,0 +1,11 @@ +# RT-Thread building script for component + +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') + Glob('*.S') +CPPPATH = [cwd] + +group = DefineGroup('Drivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/spacemit/k1/drivers/board.c b/bsp/spacemit/k1/drivers/board.c new file mode 100644 index 000000000000..bbb3a0f4bdb3 --- /dev/null +++ b/bsp/spacemit/k1/drivers/board.c @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include +#include +#include + +#if defined(RT_USING_PTP) && defined(FINSH_USING_MSH) +#include +#endif + +void rt_hw_board_init(void) +{ + rt_hw_common_setup(); +} + +void rt_hw_fdt_vendor_install_early(void *fdt) +{ + int node; + + node = fdt_path_offset(fdt, "/cpus"); + fdt_setprop_u32(fdt, node, "cpu-boot-delay-us", 100); +} diff --git a/bsp/spacemit/k1/drivers/board.h b/bsp/spacemit/k1/drivers/board.h new file mode 100644 index 000000000000..da2e9bfdd727 --- /dev/null +++ b/bsp/spacemit/k1/drivers/board.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#ifndef __BOARD_H__ +#define __BOARD_H__ + +void rt_hw_board_init(void); + +#endif /* __BOARD_H__ */ diff --git a/bsp/spacemit/k1/drivers/esos.elf b/bsp/spacemit/k1/drivers/esos.elf new file mode 100644 index 000000000000..21783ce196f7 Binary files /dev/null and b/bsp/spacemit/k1/drivers/esos.elf differ diff --git a/bsp/spacemit/k1/drivers/firmware.S b/bsp/spacemit/k1/drivers/firmware.S new file mode 100644 index 000000000000..a419183f9ec5 --- /dev/null +++ b/bsp/spacemit/k1/drivers/firmware.S @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-5-1 GuEe-GUI first version + */ + +#include + + .section ".rodata" + SPACEMIT_FIRMWARE_DEFINE esos.elf + +SPACEMIT_FIRMWARE_START + SPACEMIT_FIRMWARE_REF esos.elf +SPACEMIT_FIRMWARE_END diff --git a/bsp/spacemit/k1/rtconfig.h b/bsp/spacemit/k1/rtconfig.h new file mode 100644 index 000000000000..3750fa1296c8 --- /dev/null +++ b/bsp/spacemit/k1/rtconfig.h @@ -0,0 +1,752 @@ +#ifndef RT_CONFIG_H__ +#define RT_CONFIG_H__ + +/* RT-Thread Kernel */ + +/* klibc options */ + +/* rt_vsnprintf options */ + +/* end of rt_vsnprintf options */ + +/* rt_vsscanf options */ + +/* end of rt_vsscanf options */ + +/* rt_memset options */ + +/* end of rt_memset options */ + +/* rt_memcpy options */ + +/* end of rt_memcpy options */ + +/* rt_memmove options */ + +/* end of rt_memmove options */ + +/* rt_memcmp options */ + +/* end of rt_memcmp options */ + +/* rt_strstr options */ + +/* end of rt_strstr options */ + +/* rt_strcasecmp options */ + +/* end of rt_strcasecmp options */ + +/* rt_strncpy options */ + +/* end of rt_strncpy options */ + +/* rt_strcpy options */ + +/* end of rt_strcpy options */ + +/* rt_strncmp options */ + +/* end of rt_strncmp options */ + +/* rt_strcmp options */ + +/* end of rt_strcmp options */ + +/* rt_strlen options */ + +/* end of rt_strlen options */ + +/* rt_strnlen options */ + +/* end of rt_strnlen options */ +/* end of klibc options */ +#define RT_NAME_MAX 24 +#define RT_USING_SMP +#define RT_CPUS_NR 4 +#define RT_ALIGN_SIZE 8 +#define RT_THREAD_PRIORITY_32 +#define RT_THREAD_PRIORITY_MAX 32 +#define RT_TICK_PER_SECOND 100 +#define RT_USING_OVERFLOW_CHECK +#define RT_USING_HOOK +#define RT_HOOK_USING_FUNC_PTR +#define RT_USING_IDLE_HOOK +#define RT_IDLE_HOOK_LIST_SIZE 4 +#define IDLE_THREAD_STACK_SIZE 16384 +#define SYSTEM_THREAD_STACK_SIZE 16384 +#define RT_USING_TIMER_SOFT +#define RT_TIMER_THREAD_PRIO 4 +#define RT_TIMER_THREAD_STACK_SIZE 16384 +#define RT_USING_CPU_USAGE_TRACER +#define RT_CPU_USAGE_CALC_INTERVAL_MS 200 + +/* kservice options */ + +/* end of kservice options */ +#define RT_USING_DEBUG +#define RT_DEBUGING_ASSERT +#define RT_DEBUGING_COLOR +#define RT_DEBUGING_CONTEXT + +/* Inter-Thread communication */ + +#define RT_USING_SEMAPHORE +#define RT_USING_MUTEX +#define RT_USING_EVENT +#define RT_USING_MAILBOX +#define RT_USING_MESSAGEQUEUE +#define RT_USING_SIGNALS +/* end of Inter-Thread communication */ + +/* Memory Management */ + +#define RT_USING_MEMPOOL +#define RT_USING_SLAB +#define RT_USING_MEMHEAP +#define RT_MEMHEAP_FAST_MODE +#define RT_USING_SLAB_AS_HEAP +#define RT_USING_MEMTRACE +#define RT_USING_HEAP +/* end of Memory Management */ +#define RT_USING_DEVICE +#define RT_USING_DEVICE_OPS +#define RT_USING_INTERRUPT_INFO +#define RT_USING_CONSOLE +#define RT_CONSOLEBUF_SIZE 256 +#define RT_CONSOLE_DEVICE_NAME "uart0" +#define RT_USING_CONSOLE_OUTPUT_CTL +#define RT_VER_NUM 0x50300 +#define RT_USING_STDC_ATOMIC +#define RT_BACKTRACE_LEVEL_MAX_NR 32 +/* end of RT-Thread Kernel */ +#define ARCH_TEXT_OFFSET 0x200000 +#define ARCH_RAM_OFFSET 0 +#define ARCH_SECONDARY_CPU_STACK_SIZE 4096 +#define ARCH_HEAP_SIZE 0x4000000 +#define ARCH_INIT_PAGE_SIZE 0x200000 +#define ARCH_CPU_64BIT +#define RT_USING_CACHE +#define RT_USING_HW_ATOMIC +#define RT_USING_CPU_FFS +#define ARCH_MM_MMU +#define ARCH_RISCV +#define ARCH_RISCV_FPU +#define ARCH_RISCV_FPU_D +#define ARCH_RISCV64 + +/* RISC-V Architecture Configuration */ + +#define RT_USING_RISCV_NEW_COMMON +/* end of RISC-V Architecture Configuration */ +#define ARCH_USING_NEW_CTX_SWITCH + +/* RT-Thread Components */ + +#define RT_USING_COMPONENTS_INIT +#define RT_USING_USER_MAIN +#define RT_MAIN_THREAD_STACK_SIZE 16384 +#define RT_MAIN_THREAD_PRIORITY 10 +#define RT_USING_MSH +#define RT_USING_FINSH +#define FINSH_USING_MSH +#define FINSH_THREAD_NAME "tshell" +#define FINSH_THREAD_PRIORITY 20 +#define FINSH_THREAD_STACK_SIZE 16384 +#define FINSH_USING_HISTORY +#define FINSH_HISTORY_LINES 10 +#define FINSH_USING_SYMTAB +#define FINSH_CMD_SIZE 80 +#define MSH_USING_BUILT_IN_COMMANDS +#define FINSH_USING_DESCRIPTION +#define FINSH_ARG_MAX 10 +#define FINSH_USING_OPTION_COMPLETION + +/* DFS: device virtual file system */ + +#define RT_USING_DFS +#define DFS_USING_POSIX +#define DFS_USING_WORKDIR +#define DFS_FD_MAX 32 +#define RT_USING_DFS_V2 +#define RT_USING_DFS_ELMFAT + +/* elm-chan's FatFs, Generic FAT Filesystem Module */ + +#define RT_DFS_ELM_CODE_PAGE 437 +#define RT_DFS_ELM_WORD_ACCESS +#define RT_DFS_ELM_USE_LFN_3 +#define RT_DFS_ELM_USE_LFN 3 +#define RT_DFS_ELM_LFN_UNICODE_0 +#define RT_DFS_ELM_LFN_UNICODE 0 +#define RT_DFS_ELM_MAX_LFN 255 +#define RT_DFS_ELM_DRIVES 2 +#define RT_DFS_ELM_MAX_SECTOR_SIZE 512 +#define RT_DFS_ELM_REENTRANT +#define RT_DFS_ELM_MUTEX_TIMEOUT 3000 +#define RT_DFS_ELM_USE_EXFAT +/* end of elm-chan's FatFs, Generic FAT Filesystem Module */ +#define RT_USING_DFS_DEVFS +#define RT_USING_DFS_ROMFS +/* end of DFS: device virtual file system */ + +/* Device Drivers */ + +#define RT_USING_DM +#define RT_USING_DEVICE_IPC +#define RT_UNAMED_PIPE_NUMBER 64 +#define RT_USING_SYSTEM_WORKQUEUE +#define RT_SYSTEM_WORKQUEUE_STACKSIZE 8192 +#define RT_SYSTEM_WORKQUEUE_PRIORITY 23 +#define RT_USING_SERIAL +#define RT_USING_SERIAL_V1 +#define RT_SERIAL_USING_DMA +#define RT_SERIAL_RB_BUFSZ 64 +#define RT_USING_SERIAL_BYPASS +#define RT_SERIAL_8250 +#define RT_SERIAL_PXA +#define RT_SERIAL_EARLY_SBI +#define RT_USING_ADC +#define RT_USING_ADC_V1 +#define RT_ADC_SPACEMIT_PMIC +#define RT_USING_CLOCK_TIME +#define CLOCK_TIMER_FREQ 0 +#define RT_CLOCK_TIME_SPACEMIT_K1X +#define RT_USING_ETHERNET +#define RT_ETHERNET_K1X_EMAC +#define RT_ETHERNET_K1X_EMAC_PTP +#define RT_USING_I2C +#define RT_USING_I2C_BITOPS +#define RT_I2C_SPACEMIT_K1X +#define RT_USING_PHY_V2 +#define RT_PHY_V2_REALTEK +#define RT_USING_NULL +#define RT_USING_ZERO +#define RT_USING_RANDOM +#define RT_USING_PWM +#define RT_PWM_PXA +#define RT_USING_MTD_NOR +#define RT_USING_MTD_NOR_SPI +#define RT_USING_RTC +#define RT_USING_ALARM +#define RT_ALARM_STACK_SIZE 16384 +#define RT_ALARM_TIMESLICE 5 +#define RT_ALARM_PRIORITY 10 +#define RT_RTC_SPACEMIT_PMIC +#define RT_USING_SDIO +#define RT_SDIO_STACK_SIZE 16384 +#define RT_SDIO_THREAD_PRIORITY 15 +#define RT_MMCSD_STACK_SIZE 16384 +#define RT_MMCSD_THREAD_PRIORITY 22 +#define RT_MMCSD_MAX_PARTITION 16 +#define RT_USING_SDHCI +#define RT_SDIO_SDHCI_SPACEMIT_K1X +#define RT_USING_SPI +#define RT_USING_QSPI +#define RT_USING_SFUD +#define RT_SFUD_USING_SFDP +#define RT_SFUD_USING_FLASH_INFO_TABLE +#define RT_SFUD_USING_QSPI +#define RT_SFUD_SPI_MAX_HZ 50000000 +#define RT_DEBUG_SFUD +#define RT_SPI_K1X_QSPI +#define RT_SPI_K1X +#define RT_USING_WDT +#define RT_WDT_SPACEMIT_WATCHDOG +#define RT_USING_AUDIO +#define RT_AUDIO_REPLAY_MP_BLOCK_SIZE 4096 +#define RT_AUDIO_REPLAY_MP_BLOCK_COUNT 4 +#define RT_AUDIO_RECORD_PIPE_SIZE 8192 +#define RT_AUDIO_SPACEMIT +#define RT_AUDIO_SPACEMIT_CODEC +#define RT_AUDIO_SPACEMIT_CODEC_ES8326 +#define RT_USING_LCD +#define RT_USING_GRAPHIC +#define RT_GRAPHIC_BACKLIGHT +#define RT_GRAPHIC_BACKLIGHT_PWM +#define RT_GRAPHIC_FB +#define RT_GRAPHIC_FB_SPACEMIT +#define RT_GRAPHIC_LOGO +#define RT_GRAPHIC_LOGO_SPACEMIT_CLUT224 +#define RT_GRAPHIC_LOGO_SPACEMIT_CLUT224_PATH "../dm/graphic/logo/logo-spacemit-clut224.ppm" +#define RT_USING_HWCRYPTO +#define RT_HWCRYPTO_DEFAULT_NAME "hwcryto" +#define RT_HWCRYPTO_IV_MAX_SIZE 16 +#define RT_HWCRYPTO_KEYBIT_MAX_SIZE 256 +#define RT_HWCRYPTO_USING_AES +#define RT_HWCRYPTO_USING_AES_ECB +#define RT_HWCRYPTO_USING_AES_CBC +#define RT_HWCRYPTO_USING_RNG +#define RT_HWCRYPTO_SPACEMIT +#define RT_HWCRYPTO_RNG_SPACEMIT +#define RT_USING_PTP +#define RT_USING_LED +#define RT_LED_GPIO +#define RT_USING_INPUT +#define RT_INPUT_POWER +#define RT_INPUT_MISC +#define RT_INPUT_MISC_PWRKEY_SPACEMIT_PMIC +#define RT_USING_MBOX +#define RT_MBOX_K1X +#define RT_USING_RPMSG +#define RT_RPMSG_CHAR_MSG_MAX 64 +#define RT_RPMSG_CHAR_MSG_SIZE_MAX 256 +#define RT_USING_ATA +#define RT_ATA_AHCI +#define RT_ATA_AHCI_PCI +#define RT_USING_NVME +#define RT_USING_NVME_IO_QUEUE 4 +#define RT_NVME_PCI +#define RT_USING_BLK + +/* Partition Types */ + +#define RT_BLK_PARTITION_DFS +#define RT_BLK_PARTITION_EFI +/* end of Partition Types */ +#define RT_USING_SCSI +#define RT_SCSI_SD +#define RT_USING_DVFS +#define RT_USING_DVFS_EVENT +#define RT_USING_DVFS_OPP_RETRY_MAX 10 + +/* DVFS Event Drivers */ + +/* DVFS CPUfreq Drivers */ + +#define RT_DVFS_SPACEMIT_CPUFREQ + +/* DVFS Devfreq Drivers */ + +#define RT_USING_REGULATOR +#define RT_REGULATOR_FIXED +#define RT_REGULATOR_GPIO +#define RT_REGULATOR_SPACEMIT_PMIC +#define RT_USING_RESET +#define RT_RESET_SPACEMIT_K1 + +/* Power Management (PM) Domains device drivers */ + +#define RT_PMDOMAIN_K1X +/* end of Power Management (PM) Domains device drivers */ +#define RT_USING_POWER_RESET +#define RT_POWER_RESET_REBOOT_SPACEMIT +#define RT_USING_THERMAL + +/* Thermal Sensors Drivers */ + +#define RT_THERMAL_K1X + +/* Thermal Cool Drivers */ + +#define RT_THERMAL_COOL_DVFS +#define RT_THERMAL_COOL_PWM_FAN +#define RT_USING_VIRTIO +#define RT_VIRTIO_NET +#define RT_VIRTIO_RPMSG +#define RT_USING_NVMEM +#define RT_NVMEM_SPACEMIT_EFUSE +#define RT_USING_DMA +#define RT_DMA_MMP_PDMA +#define RT_DMA_MMP_PDMA_SUPPORT_64BIT +#define RT_USING_MFD +#define RT_MFD_SYSCON +#define RT_MFD_SPACEMIT_PMIC +#define RT_USING_OFW +#define RT_FDT_EARLYCON_MSG_SIZE 128 +#define RT_USING_OFW_BUS_RANGES_NUMBER 8 +#define RT_USING_PCI +#define RT_PCI_MSI +#define RT_PCI_ENDPOINT +#define RT_PCI_SYS_64BIT +#define RT_PCI_CACHE_LINE_SIZE 8 + +/* PCI Device Drivers */ + +#define RT_PCI_DW +#define RT_PCI_DW_HOST +#define RT_PCI_DW_EP +#define RT_PCI_DW_SPACEMIT_K1X +#define RT_USING_PIC +#define MAX_HANDLERS 1024 +#define RT_PIC_RISCV_INTC +#define RT_PIC_SIFIVE_PLIC +#define RT_USING_PIN +#define RT_PIN_K1X +#define RT_USING_PINCTRL +#define RT_PINCTRL_SINGLE +#define RT_PINCTRL_SPACEMIT_PMIC +#define RT_USING_CLK +#define RT_CLK_SPACEMIT +#define RT_CLK_SPACEMIT_K1X + +/* SoC (System on Chip) Drivers */ + +#define RT_SOC_SPACEMIT_K1X_RPROC +#define RT_SOC_CHIP_MEDIA_JPU +#define RT_SOC_SPACEMIT_V2D +#define RT_SOC_SPACEMIT_K1X_TCM +#define RT_SOC_SPACEMIT_SOCINFO +/* end of SoC (System on Chip) Drivers */ +/* end of Device Drivers */ + +/* C/C++ and POSIX layer */ + +/* ISO-ANSI C layer */ + +/* Timezone and Daylight Saving Time */ + +#define RT_LIBC_USING_LIGHT_TZ_DST +#define RT_LIBC_TZ_DEFAULT_HOUR 8 +#define RT_LIBC_TZ_DEFAULT_MIN 0 +#define RT_LIBC_TZ_DEFAULT_SEC 0 +/* end of Timezone and Daylight Saving Time */ +/* end of ISO-ANSI C layer */ + +/* POSIX (Portable Operating System Interface) layer */ + +#define RT_USING_POSIX_FS +#define RT_USING_POSIX_DEVIO +#define RT_USING_POSIX_STDIO +#define RT_USING_POSIX_POLL +#define RT_USING_POSIX_SELECT +#define RT_USING_POSIX_TERMIOS +#define RT_USING_POSIX_AIO +#define RT_USING_POSIX_DELAY +#define RT_USING_POSIX_CLOCK +#define RT_USING_POSIX_TIMER + +/* Interprocess Communication (IPC) */ + +#define RT_USING_POSIX_PIPE +#define RT_USING_POSIX_PIPE_SIZE 512 + +/* Socket is in the 'Network' category */ + +/* end of Interprocess Communication (IPC) */ +/* end of POSIX (Portable Operating System Interface) layer */ +/* end of C/C++ and POSIX layer */ + +/* Network */ + +#define RT_USING_SAL +#define SAL_INTERNET_CHECK +#define SOCKET_TABLE_STEP_LEN 4 + +/* Docking with protocol stacks */ + +#define SAL_USING_LWIP +/* end of Docking with protocol stacks */ +#define SAL_USING_POSIX +#define RT_USING_NETDEV +#define NETDEV_USING_IFCONFIG +#define NETDEV_USING_PING +#define NETDEV_USING_NETSTAT +#define NETDEV_USING_AUTO_DEFAULT +#define NETDEV_IPV4 1 +#define NETDEV_IPV6 0 +#define RT_USING_LWIP +#define RT_USING_LWIP203 +#define RT_USING_LWIP_VER_NUM 0x20003 +#define RT_LWIP_MEM_ALIGNMENT 4 +#define RT_LWIP_IGMP +#define RT_LWIP_ICMP +#define RT_LWIP_DNS +#define RT_LWIP_DHCP +#define IP_SOF_BROADCAST 1 +#define IP_SOF_BROADCAST_RECV 1 + +/* Static IPv4 Address */ + +#define RT_LWIP_IPADDR "192.168.1.30" +#define RT_LWIP_GWADDR "192.168.1.1" +#define RT_LWIP_MSKADDR "255.255.255.0" +/* end of Static IPv4 Address */ +#define RT_LWIP_UDP +#define RT_LWIP_TCP +#define RT_LWIP_RAW +#define RT_MEMP_NUM_NETCONN 8 +#define RT_LWIP_PBUF_NUM 16 +#define RT_LWIP_RAW_PCB_NUM 4 +#define RT_LWIP_UDP_PCB_NUM 4 +#define RT_LWIP_TCP_PCB_NUM 4 +#define RT_LWIP_TCP_SEG_NUM 40 +#define RT_LWIP_TCP_SND_BUF 8196 +#define RT_LWIP_TCP_WND 8196 +#define RT_LWIP_TCPTHREAD_PRIORITY 10 +#define RT_LWIP_TCPTHREAD_MBOX_SIZE 8 +#define RT_LWIP_TCPTHREAD_STACKSIZE 8192 +#define RT_LWIP_ETHTHREAD_PRIORITY 12 +#define RT_LWIP_ETHTHREAD_STACKSIZE 8192 +#define RT_LWIP_ETHTHREAD_MBOX_SIZE 8 +#define LWIP_NETIF_STATUS_CALLBACK 1 +#define LWIP_NETIF_LINK_CALLBACK 1 +#define RT_LWIP_NETIF_NAMESIZE 6 +#define SO_REUSE 1 +#define LWIP_SO_RCVTIMEO 1 +#define LWIP_SO_SNDTIMEO 1 +#define LWIP_SO_RCVBUF 1 +#define LWIP_SO_LINGER 0 +#define LWIP_NETIF_LOOPBACK 0 +#define RT_LWIP_USING_PING +/* end of Network */ + +/* Memory protection */ + +/* end of Memory protection */ + +/* Utilities */ + +#define RT_USING_RESOURCE_ID +#define RT_USING_ADT +#define RT_USING_ADT_AVL +#define RT_USING_ADT_BITMAP +#define RT_USING_ADT_HASHMAP +#define RT_USING_ADT_REF +/* end of Utilities */ + +/* Memory management */ + +#define RT_PAGE_MPR_SIZE_DYNAMIC +#define RT_PAGE_AFFINITY_BLOCK_SIZE 0x1000 +#define RT_PAGE_MAX_ORDER 11 +#define RT_USING_MEMBLOCK +#define RT_INIT_MEMORY_REGIONS 128 + +/* Debugging */ + +/* end of Debugging */ +/* end of Memory management */ + +/* Using USB legacy version */ + +/* end of Using USB legacy version */ +/* end of RT-Thread Components */ + +/* RT-Thread Utestcases */ + +/* end of RT-Thread Utestcases */ + +/* RT-Thread online packages */ + +/* IoT - internet of things */ + + +/* Wi-Fi */ + +/* Marvell WiFi */ + +/* end of Marvell WiFi */ + +/* Wiced WiFi */ + +/* end of Wiced WiFi */ + +/* CYW43012 WiFi */ + +/* end of CYW43012 WiFi */ + +/* BL808 WiFi */ + +/* end of BL808 WiFi */ + +/* CYW43439 WiFi */ + +/* end of CYW43439 WiFi */ +/* end of Wi-Fi */ + +/* IoT Cloud */ + +/* end of IoT Cloud */ +/* end of IoT - internet of things */ + +/* security packages */ + +/* end of security packages */ + +/* language packages */ + +/* JSON: JavaScript Object Notation, a lightweight data-interchange format */ + +/* end of JSON: JavaScript Object Notation, a lightweight data-interchange format */ + +/* XML: Extensible Markup Language */ + +/* end of XML: Extensible Markup Language */ +/* end of language packages */ + +/* multimedia packages */ + +/* LVGL: powerful and easy-to-use embedded GUI library */ + +/* end of LVGL: powerful and easy-to-use embedded GUI library */ + +/* u8g2: a monochrome graphic library */ + +/* end of u8g2: a monochrome graphic library */ +/* end of multimedia packages */ + +/* tools packages */ + +/* end of tools packages */ + +/* system packages */ + +/* enhanced kernel services */ + +/* end of enhanced kernel services */ + +/* acceleration: Assembly language or algorithmic acceleration packages */ + +/* end of acceleration: Assembly language or algorithmic acceleration packages */ + +/* CMSIS: ARM Cortex-M Microcontroller Software Interface Standard */ + +/* end of CMSIS: ARM Cortex-M Microcontroller Software Interface Standard */ + +/* Micrium: Micrium software products porting for RT-Thread */ + +/* end of Micrium: Micrium software products porting for RT-Thread */ +/* end of system packages */ + +/* peripheral libraries and drivers */ + +/* HAL & SDK Drivers */ + +/* STM32 HAL & SDK Drivers */ + +/* end of STM32 HAL & SDK Drivers */ + +/* Infineon HAL Packages */ + +/* end of Infineon HAL Packages */ + +/* Kendryte SDK */ + +/* end of Kendryte SDK */ + +/* MM32 HAL & SDK Drivers */ + +/* end of MM32 HAL & SDK Drivers */ + +/* WCH HAL & SDK Drivers */ + +/* end of WCH HAL & SDK Drivers */ + +/* AT32 HAL & SDK Drivers */ + +/* end of AT32 HAL & SDK Drivers */ + +/* HC32 DDL Drivers */ + +/* end of HC32 DDL Drivers */ + +/* NXP HAL & SDK Drivers */ + +/* end of NXP HAL & SDK Drivers */ + +/* NUVOTON Drivers */ + +/* end of NUVOTON Drivers */ + +/* GD32 Drivers */ + +/* end of GD32 Drivers */ + +/* HPMicro SDK */ + +/* end of HPMicro SDK */ + +/* FT32 HAL & SDK Drivers */ + +/* end of FT32 HAL & SDK Drivers */ + +/* NOVOSNS Drivers */ + +/* end of NOVOSNS Drivers */ + +/* N32 Drivers */ + +/* end of N32 Drivers */ +/* end of HAL & SDK Drivers */ + +/* sensors drivers */ + +/* end of sensors drivers */ + +/* touch drivers */ + +/* end of touch drivers */ +/* end of peripheral libraries and drivers */ + +/* AI packages */ + +/* end of AI packages */ + +/* Signal Processing and Control Algorithm Packages */ + +/* end of Signal Processing and Control Algorithm Packages */ + +/* miscellaneous packages */ + +/* project laboratory */ + +/* end of project laboratory */ + +/* samples: kernel and components samples */ + +/* end of samples: kernel and components samples */ + +/* entertainment: terminal games and other interesting software packages */ + +/* end of entertainment: terminal games and other interesting software packages */ +/* end of miscellaneous packages */ + +/* Arduino libraries */ + + +/* Projects and Demos */ + +/* end of Projects and Demos */ + +/* Sensors */ + +/* end of Sensors */ + +/* Display */ + +/* end of Display */ + +/* Timing */ + +/* end of Timing */ + +/* Data Processing */ + +/* end of Data Processing */ + +/* Data Storage */ + +/* Communication */ + +/* end of Communication */ + +/* Device Control */ + +/* end of Device Control */ + +/* Other */ + +/* end of Other */ + +/* Signal IO */ + +/* end of Signal IO */ + +/* Uncategorized */ + +/* end of Arduino libraries */ +/* end of RT-Thread online packages */ +#define SOC_SPACEMIT_K1 + +#endif diff --git a/bsp/spacemit/k1/rtconfig.py b/bsp/spacemit/k1/rtconfig.py new file mode 100644 index 000000000000..84932ce28a06 --- /dev/null +++ b/bsp/spacemit/k1/rtconfig.py @@ -0,0 +1,57 @@ +import os + +# toolchains options +ARCH ='risc-v' +CPU ='' +CROSS_TOOL ='gcc' +RISCV_ABI = os.getenv('RTT_RISCV_ABI') + +RTT_ROOT = os.getenv('RTT_ROOT') or os.path.join(os.getcwd(), '..', '..', '..') + +if os.getenv('RTT_CC'): + CROSS_TOOL = os.getenv('RTT_CC') + +if CROSS_TOOL == 'gcc': + PLATFORM = 'gcc' + EXEC_PATH = os.getenv('RTT_EXEC_PATH') or '/usr/bin' +else: + print('Please make sure your toolchains is GNU GCC!') + exit(0) + +BUILD = 'debug' + +if PLATFORM == 'gcc': + # toolchains + PREFIX = os.getenv('RTT_CC_PREFIX') or 'riscv64-unknown-elf-' + CC = PREFIX + 'gcc' + CXX = PREFIX + 'g++' + CPP = PREFIX + 'cpp' + AS = PREFIX + 'gcc' + AR = PREFIX + 'ar' + LINK = PREFIX + 'gcc' + TARGET_EXT = 'elf' + SIZE = PREFIX + 'size' + OBJDUMP = PREFIX + 'objdump' + OBJCPY = PREFIX + 'objcopy' + + DEVICE = ' -mcmodel=medany -march=rv64imafdc ' + if RISCV_ABI: + DEVICE += ' -mabi={} '.format(RISCV_ABI) + # DEVICE = ' -mcpu=spacemit-x60 -march=rv64gc_zba_zbb_zbc_zbs -mabi=lp64d ' + CPPFLAGS= ' -nostdinc -undef -E -P -x assembler-with-cpp' + CFLAGS = DEVICE + '-ffreestanding -flax-vector-conversions -Wall -Wno-cpp -fno-common -ffunction-sections -fdata-sections -fstrict-volatile-bitfields -fdiagnostics-color=always' + AFLAGS = ' -c' + DEVICE + ' -x assembler-with-cpp -D__ASSEMBLY__ ' + LFLAGS = DEVICE + ' -nostartfiles -Wl,--gc-sections,-Map=rtthread.map,-cref,-u,_start -T link.lds' + ' -lsupc++ -lgcc -static' + CPATH = '' + LPATH = '' + + if BUILD == 'debug': + CFLAGS += ' -O0 -ggdb -fvar-tracking ' + AFLAGS += ' -ggdb' + else: + CFLAGS += ' -O2 -Os' + + CXXFLAGS = CFLAGS + +DUMP_ACTION = OBJDUMP + ' -D -S $TARGET > rtthread.asm\n' +POST_ACTION = OBJCPY + ' -O binary $TARGET rtthread.bin\n' + SIZE + ' $TARGET \n'