| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,7 +14,6 @@ | |
| #ifndef __ARCH_ROMSTAGE_H__ | ||
| #define __ARCH_ROMSTAGE_H__ | ||
|
|
||
| #include <stddef.h> | ||
| #include <stdint.h> | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,7 +12,6 @@ | |
| # | ||
|
|
||
| romstage-y += fixme.c | ||
|
|
||
| ramstage-y += fixme.c | ||
| ramstage-y += chip_name.c | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,7 +12,7 @@ | |
| */ | ||
|
|
||
| SECTIONS { | ||
| . = 0xffffffc0; | ||
| .fit_pointer (.): { | ||
| KEEP(*(.fit_pointer)) | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -35,16 +35,4 @@ config IED_REGION_SIZE | |
| config SMM_RESERVED_SIZE | ||
| hex | ||
| default 0x100000 | ||
| endif | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,7 @@ | ||
| config MICROCODE_UPDATE_PRE_RAM | ||
| bool | ||
| depends on SUPPORT_CPU_UCODE_IN_CBFS | ||
| default y | ||
| help | ||
| Select this option if you want to update the microcode | ||
| during the cache as ram setup. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,23 @@ | ||
| /* | ||
| * This file is part of the coreboot project. | ||
| * | ||
| * This program is free software; you can redistribute it and/or modify | ||
| * it under the terms of the GNU General Public License as published by | ||
| * the Free Software Foundation; version 2 of the License. | ||
| * | ||
| * This program is distributed in the hope that it will be useful, | ||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| * GNU General Public License for more details. | ||
| */ | ||
|
|
||
| gdtptr16_offset = gdtptr16 & 0xffff; | ||
| nullidt_offset = nullidt & 0xffff; | ||
|
|
||
| /* Symbol _start16bit must be aligned to 4kB to start AP CPUs with | ||
| * Startup IPI message without RAM. | ||
| */ | ||
| #if CONFIG(SIPI_VECTOR_IN_ROM) | ||
| _bogus = ASSERT((_start16bit & 0xfff) == 0, "Symbol _start16bit is not at 4 KiB boundary"); | ||
| ap_sipi_vector_in_rom = (_start16bit >> 12) & 0xff; | ||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| /* | ||
| * This file is part of the coreboot project. | ||
| * | ||
| * This program is free software; you can redistribute it and/or modify | ||
| * it under the terms of the GNU General Public License as published by | ||
| * the Free Software Foundation; version 2 of the License. | ||
| * | ||
| * This program is distributed in the hope that it will be useful, | ||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| * GNU General Public License for more details. | ||
| */ | ||
|
|
||
| #include <bootblock_common.h> | ||
| #include <halt.h> | ||
| #include <timestamp.h> | ||
| #include <amdblocks/amd_pci_mmconf.h> | ||
| #include <amdblocks/biosram.h> | ||
| #include <arch/bootblock.h> | ||
| #include <cpu/amd/msr.h> | ||
| #include <cpu/x86/mtrr.h> | ||
| #include <cpu/x86/lapic.h> | ||
|
|
||
| #define EARLY_VMTRR_FLASH 6 | ||
|
|
||
| static void set_early_mtrrs(void) | ||
| { | ||
| /* Cache the ROM to speed up booting */ | ||
| set_var_mtrr(EARLY_VMTRR_FLASH, OPTIMAL_CACHE_ROM_BASE, | ||
| OPTIMAL_CACHE_ROM_SIZE, MTRR_TYPE_WRPROT); | ||
| } | ||
|
|
||
| void bootblock_soc_early_init(void) | ||
| { | ||
| bootblock_early_southbridge_init(); | ||
| } | ||
|
|
||
| asmlinkage void bootblock_c_entry(uint64_t base_timestamp) | ||
| { | ||
| enable_pci_mmconf(); | ||
| set_early_mtrrs(); | ||
|
|
||
| if (CONFIG(UDELAY_LAPIC)) | ||
| enable_lapic(); | ||
|
|
||
| bootblock_main_with_basetime(base_timestamp); | ||
| } | ||
|
|
||
| asmlinkage void ap_bootblock_c_entry(void) | ||
| { | ||
| enable_pci_mmconf(); | ||
| set_early_mtrrs(); | ||
|
|
||
| if (CONFIG(UDELAY_LAPIC)) | ||
| enable_lapic(); | ||
|
|
||
| void (*ap_romstage_entry)(void) = get_ap_entry_ptr(); | ||
| ap_romstage_entry(); /* execution does not return */ | ||
| halt(); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| ## | ||
| ## This file is part of the coreboot project. | ||
| ## | ||
| ## Copyright 2019 Analogix Semiconductor. | ||
| ## | ||
| ## This program is free software; you can redistribute it and/or modify | ||
| ## it under the terms of the GNU General Public License as published by | ||
| ## the Free Software Foundation; version 2 of the License. | ||
| ## | ||
| ## This program is distributed in the hope that it will be useful, | ||
| ## but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| ## GNU General Public License for more details. | ||
| ## | ||
|
|
||
| config DRIVER_ANALOGIX_ANX7625 | ||
| bool |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,363 @@ | ||
| /* SPDX-License-Identifier: GPL-2.0-only */ | ||
| /* | ||
| * Copyright(c) 2016, Analogix Semiconductor. All rights reserved. | ||
| * | ||
| */ | ||
|
|
||
|
|
||
| #include <edid.h> | ||
| #include <types.h> | ||
|
|
||
| #ifndef __ANX7625_H__ | ||
| #define __ANX7625_H__ | ||
|
|
||
| #ifndef LOG_TAG | ||
| #define LOG_TAG "anx7625dp" | ||
| #endif | ||
|
|
||
| #define ANX7625_DRV_VERSION "0.1.04" | ||
|
|
||
| /* Loading OCM re-trying times */ | ||
| #define OCM_LOADING_TIME 10 | ||
|
|
||
| /********* ANX7625 Register **********/ | ||
| #define ANXI2CSIM | ||
| #ifdef ANXI2CSIM | ||
| #define TX_P0_ADDR 0x38 | ||
| #define TX_P1_ADDR 0x3D | ||
| #define TX_P2_ADDR 0x39 | ||
| #define RX_P0_ADDR 0x3F | ||
| #define RX_P1_ADDR 0x42 | ||
| #define RX_P2_ADDR 0x2A | ||
| #define TCPC_INTERFACE_ADDR 0x2C | ||
| #else | ||
| #define TX_P0_ADDR 0x70 | ||
| #define TX_P1_ADDR 0x7A | ||
| #define TX_P2_ADDR 0x72 | ||
| #define RX_P0_ADDR 0x7e | ||
| #define RX_P1_ADDR 0x84 | ||
| #define RX_P2_ADDR 0x54 | ||
| #define TCPC_INTERFACE_ADDR 0x58 | ||
| #endif | ||
|
|
||
| #define RSVD_00_ADDR 0x00 | ||
| #define RSVD_D1_ADDR 0xD1 | ||
| #define RSVD_60_ADDR 0x60 | ||
| #define RSVD_39_ADDR 0x39 | ||
| #define RSVD_7F_ADDR 0x7F | ||
|
|
||
| /* anx7625 clock frequency in Hz */ | ||
| #define XTAL_FRQ (27*1000000) | ||
|
|
||
| #define POST_DIVIDER_MIN 1 | ||
| #define POST_DIVIDER_MAX 16 | ||
| #define PLL_OUT_FREQ_MIN 520000000UL | ||
| #define PLL_OUT_FREQ_MAX 730000000UL | ||
| #define PLL_OUT_FREQ_ABS_MIN 300000000UL | ||
| #define PLL_OUT_FREQ_ABS_MAX 800000000UL | ||
| #define MAX_UNSIGNED_24BIT 16777215UL | ||
|
|
||
| /***************************************************************/ | ||
| /* Register definition of device address 0x58 */ | ||
|
|
||
| #define PRODUCT_ID_L 0x02 | ||
| #define PRODUCT_ID_H 0x03 | ||
|
|
||
| #define INTR_ALERT_1 0xCC | ||
| #define INTR_SOFTWARE_INT (1<<3) | ||
| #define INTR_RECEIVED_MSG (1<<5) | ||
|
|
||
| #define SYSTEM_STSTUS 0x45 | ||
| #define INTERFACE_CHANGE_INT 0x44 | ||
| #define HPD_STATUS_CHANGE 0x80 | ||
| #define HPD_STATUS 0x80 | ||
|
|
||
| /******** END of I2C Address 0x58 ********/ | ||
|
|
||
| /***************************************************************/ | ||
| /* Register definition of device address 0x70 */ | ||
| #define I2C_ADDR_70_DPTX 0x70 | ||
|
|
||
| #define SP_TX_LINK_BW_SET_REG 0xA0 | ||
| #define SP_TX_LANE_COUNT_SET_REG 0xA1 | ||
|
|
||
| #define M_VID_0 0xC0 | ||
| #define M_VID_1 0xC1 | ||
| #define M_VID_2 0xC2 | ||
| #define N_VID_0 0xC3 | ||
| #define N_VID_1 0xC4 | ||
| #define N_VID_2 0xC5 | ||
|
|
||
| /***************************************************************/ | ||
| /* Register definition of device address 0x72 */ | ||
| #define AUX_RST 0x04 | ||
| #define RST_CTRL2 0x07 | ||
|
|
||
| #define SP_TX_TOTAL_LINE_STA_L 0x24 | ||
| #define SP_TX_TOTAL_LINE_STA_H 0x25 | ||
| #define SP_TX_ACT_LINE_STA_L 0x26 | ||
| #define SP_TX_ACT_LINE_STA_H 0x27 | ||
| #define SP_TX_V_F_PORCH_STA 0x28 | ||
| #define SP_TX_V_SYNC_STA 0x29 | ||
| #define SP_TX_V_B_PORCH_STA 0x2A | ||
| #define SP_TX_TOTAL_PIXEL_STA_L 0x2B | ||
| #define SP_TX_TOTAL_PIXEL_STA_H 0x2C | ||
| #define SP_TX_ACT_PIXEL_STA_L 0x2D | ||
| #define SP_TX_ACT_PIXEL_STA_H 0x2E | ||
| #define SP_TX_H_F_PORCH_STA_L 0x2F | ||
| #define SP_TX_H_F_PORCH_STA_H 0x30 | ||
| #define SP_TX_H_SYNC_STA_L 0x31 | ||
| #define SP_TX_H_SYNC_STA_H 0x32 | ||
| #define SP_TX_H_B_PORCH_STA_L 0x33 | ||
| #define SP_TX_H_B_PORCH_STA_H 0x34 | ||
|
|
||
| #define SP_TX_VID_CTRL 0x84 | ||
| #define SP_TX_BPC_MASK 0xE0 | ||
| #define SP_TX_BPC_6 0x00 | ||
| #define SP_TX_BPC_8 0x20 | ||
| #define SP_TX_BPC_10 0x40 | ||
| #define SP_TX_BPC_12 0x60 | ||
|
|
||
| #define VIDEO_BIT_MATRIX_12 0x4c | ||
|
|
||
| #define AUDIO_CHANNEL_STATUS_1 0xd0 | ||
| #define AUDIO_CHANNEL_STATUS_2 0xd1 | ||
| #define AUDIO_CHANNEL_STATUS_3 0xd2 | ||
| #define AUDIO_CHANNEL_STATUS_4 0xd3 | ||
| #define AUDIO_CHANNEL_STATUS_5 0xd4 | ||
| #define AUDIO_CHANNEL_STATUS_6 0xd5 | ||
| #define TDM_SLAVE_MODE 0x10 | ||
| #define I2S_SLAVE_MODE 0x08 | ||
|
|
||
| #define AUDIO_CONTROL_REGISTER 0xe6 | ||
| #define TDM_TIMING_MODE 0x08 | ||
|
|
||
| #define I2C_ADDR_72_DPTX 0x72 | ||
|
|
||
| #define VIDEO_CONTROL_0 0x08 | ||
|
|
||
| #define ACTIVE_LINES_L 0x14 | ||
| #define ACTIVE_LINES_H 0x15 /* note: bit[7:6] are reserved */ | ||
| #define VERTICAL_FRONT_PORCH 0x16 | ||
| #define VERTICAL_SYNC_WIDTH 0x17 | ||
| #define VERTICAL_BACK_PORCH 0x18 | ||
|
|
||
| #define HORIZONTAL_TOTAL_PIXELS_L 0x19 | ||
| #define HORIZONTAL_TOTAL_PIXELS_H 0x1A /* note: bit[7:6] are reserved */ | ||
| #define HORIZONTAL_ACTIVE_PIXELS_L 0x1B | ||
| #define HORIZONTAL_ACTIVE_PIXELS_H 0x1C /* note: bit[7:6] are reserved */ | ||
| #define HORIZONTAL_FRONT_PORCH_L 0x1D | ||
| #define HORIZONTAL_FRONT_PORCH_H 0x1E /* note: bit[7:4] are reserved */ | ||
| #define HORIZONTAL_SYNC_WIDTH_L 0x1F | ||
| #define HORIZONTAL_SYNC_WIDTH_H 0x20 /* note: bit[7:4] are reserved */ | ||
| #define HORIZONTAL_BACK_PORCH_L 0x21 | ||
| #define HORIZONTAL_BACK_PORCH_H 0x22 /* note: bit[7:4] are reserved */ | ||
|
|
||
| /******** END of I2C Address 0x72 *********/ | ||
| /***************************************************************/ | ||
| /* Register definition of device address 0x7e */ | ||
|
|
||
| #define I2C_ADDR_7E_FLASH_CONTROLLER 0x7E | ||
|
|
||
| #define XTAL_FRQ_SEL 0x3F | ||
| /* bit field positions */ | ||
| #define XTAL_FRQ_SEL_POS 5 | ||
| /* bit field values */ | ||
| #define XTAL_FRQ_19M2 (0 << XTAL_FRQ_SEL_POS) | ||
| #define XTAL_FRQ_27M (4 << XTAL_FRQ_SEL_POS) | ||
|
|
||
| #define R_DSC_CTRL_0 0x40 | ||
| #define READ_STATUS_EN 7 | ||
| #define CLK_1MEG_RB 6 /* 1MHz clock reset; 0=reset, 0=reset release */ | ||
| #define DSC_BIST_DONE 1 /* bit[5:1]: 1=DSC MBIST pass */ | ||
| #define DSC_EN 0x01 /* 1=DSC enabled, 0=DSC disabled */ | ||
|
|
||
| #define OCM_FW_VERSION 0x31 | ||
| #define OCM_FW_REVERSION 0x32 | ||
|
|
||
| #define AP_AUX_ADDR_7_0 0x11 | ||
| #define AP_AUX_ADDR_15_8 0x12 | ||
| #define AP_AUX_ADDR_19_16 0x13 | ||
|
|
||
| /* note: bit[0:3] AUX status, bit 4 op_en, bit 5 address only */ | ||
| #define AP_AUX_CTRL_STATUS 0x14 | ||
| #define AP_AUX_CTRL_OP_EN 0x10 | ||
| #define AP_AUX_CTRL_ADDRONLY 0x20 | ||
|
|
||
| #define AP_AUX_BUFF_START 0x15 | ||
| #define PIXEL_CLOCK_L 0x25 | ||
| #define PIXEL_CLOCK_H 0x26 | ||
|
|
||
| #define AP_AUX_COMMAND 0x27 /* com+len */ | ||
| /* bit 0&1: 3D video structure */ | ||
| /* 0x01: frame packing, 0x02:Line alternative, 0x03:Side-by-side(full) */ | ||
| #define AP_AV_STATUS 0x28 | ||
| #define AP_VIDEO_CHG (1<<2) | ||
| #define AP_AUDIO_CHG (1<<3) | ||
| #define AP_MIPI_MUTE (1<<4) /* 1:MIPI input mute, 0: ummute */ | ||
| #define AP_MIPI_RX_EN (1<<5) /* 1: MIPI RX input in 0: no RX in */ | ||
| #define AP_DISABLE_PD (1<<6) | ||
| #define AP_DISABLE_DISPLAY (1<<7) | ||
| /***************************************************************/ | ||
| /* Register definition of device address 0x84 */ | ||
| #define MIPI_PHY_CONTROL_3 0x03 | ||
| #define MIPI_HS_PWD_CLK 7 | ||
| #define MIPI_HS_RT_CLK 6 | ||
| #define MIPI_PD_CLK 5 | ||
| #define MIPI_CLK_RT_MANUAL_PD_EN 4 | ||
| #define MIPI_CLK_HS_MANUAL_PD_EN 3 | ||
| #define MIPI_CLK_DET_DET_BYPASS 2 | ||
| #define MIPI_CLK_MISS_CTRL 1 | ||
| #define MIPI_PD_LPTX_CH_MANUAL_PD_EN 0 | ||
|
|
||
| #define MIPI_LANE_CTRL_0 0x05 | ||
| #define MIPI_TIME_HS_PRPR 0x08 | ||
|
|
||
| /* After MIPI RX protocol layer received this many video frames, */ | ||
| /* protocol layer starts to reconstruct video stream from PHY */ | ||
| #define MIPI_VIDEO_STABLE_CNT 0x0A | ||
|
|
||
| #define MIPI_LANE_CTRL_10 0x0F | ||
| #define MIPI_DIGITAL_ADJ_1 0x1B | ||
|
|
||
| #define MIPI_PLL_M_NUM_23_16 0x1E | ||
| #define MIPI_PLL_M_NUM_15_8 0x1F | ||
| #define MIPI_PLL_M_NUM_7_0 0x20 | ||
| #define MIPI_PLL_N_NUM_23_16 0x21 | ||
| #define MIPI_PLL_N_NUM_15_8 0x22 | ||
| #define MIPI_PLL_N_NUM_7_0 0x23 | ||
|
|
||
| #define MIPI_DIGITAL_PLL_6 0x2A | ||
| /* bit[7:6]: VCO band control, only effective */ | ||
| /* when MIPI_PLL_FORCE_BAND_EN (0x84:0x2B[6]) is 1 */ | ||
| #define MIPI_M_NUM_READY 0x10 | ||
| #define MIPI_N_NUM_READY 0x08 | ||
| #define STABLE_INTEGER_CNT_EN 0x04 | ||
| #define MIPI_PLL_TEST_BIT 0 | ||
| /* bit[1:0]: test point output select - */ | ||
| /* 00: VCO power, 01: dvdd_pdt, 10: dvdd, 11: vcox */ | ||
|
|
||
| #define MIPI_DIGITAL_PLL_7 0x2B | ||
| #define MIPI_PLL_FORCE_N_EN 7 | ||
| #define MIPI_PLL_FORCE_BAND_EN 6 | ||
|
|
||
| #define MIPI_PLL_VCO_TUNE_REG 4 | ||
| /* bit[5:4]: VCO metal capacitance - */ | ||
| /* 00: +20% fast, 01: +10% fast (default), 10: typical, 11: -10% slow */ | ||
| #define MIPI_PLL_VCO_TUNE_REG_VAL 0x30 | ||
|
|
||
| #define MIPI_PLL_PLL_LDO_BIT 2 | ||
| /* bit[3:2]: vco_v2i power - */ | ||
| /* 00: 1.40V, 01: 1.45V (default), 10: 1.50V, 11: 1.55V */ | ||
| #define MIPI_PLL_RESET_N 0x02 | ||
| #define MIPI_FRQ_FORCE_NDET 0 | ||
|
|
||
| #define MIPI_ALERT_CLR_0 0x2D | ||
| #define HS_link_error_clear 7 | ||
| /* This bit itself is S/C, and it clears 0x84:0x31[7] */ | ||
|
|
||
| #define MIPI_ALERT_OUT_0 0x31 | ||
| #define check_sum_err_hs_sync 7 | ||
| /* This bit is cleared by 0x84:0x2D[7] */ | ||
|
|
||
| #define MIPI_DIGITAL_PLL_8 0x33 | ||
| #define MIPI_POST_DIV_VAL 4 | ||
| /* n means divided by (n+1), n = 0~15 */ | ||
| #define MIPI_EN_LOCK_FRZ 3 | ||
| #define MIPI_FRQ_COUNTER_RST 2 | ||
| #define MIPI_FRQ_SET_REG_8 1 | ||
| /* bit 0 is reserved */ | ||
|
|
||
| #define MIPI_DIGITAL_PLL_9 0x34 | ||
|
|
||
| #define MIPI_DIGITAL_PLL_16 0x3B | ||
| #define MIPI_FRQ_FREEZE_NDET 7 | ||
| #define MIPI_FRQ_REG_SET_ENABLE 6 | ||
| #define MIPI_REG_FORCE_SEL_EN 5 | ||
| #define MIPI_REG_SEL_DIV_REG 4 | ||
| #define MIPI_REG_FORCE_PRE_DIV_EN 3 | ||
| /* bit 2 is reserved */ | ||
| #define MIPI_FREF_D_IND 1 | ||
| #define REF_CLK_27000kHz 1 | ||
| #define REF_CLK_19200kHz 0 | ||
| #define MIPI_REG_PLL_PLL_TEST_ENABLE 0 | ||
|
|
||
| #define MIPI_DIGITAL_PLL_18 0x3D | ||
| #define FRQ_COUNT_RB_SEL 7 | ||
| #define REG_FORCE_POST_DIV_EN 6 | ||
| #define MIPI_DPI_SELECT 5 | ||
| #define SELECT_DSI 1 | ||
| #define SELECT_DPI 0 | ||
| #define REG_BAUD_DIV_RATIO 0 | ||
|
|
||
| #define H_BLANK_L 0x3E | ||
| /* for DSC only */ | ||
| #define H_BLANK_H 0x3F | ||
| /* for DSC only; note: bit[7:6] are reserved */ | ||
| #define MIPI_SWAP 0x4A | ||
| #define MIPI_SWAP_CH0 7 | ||
| #define MIPI_SWAP_CH1 6 | ||
| #define MIPI_SWAP_CH2 5 | ||
| #define MIPI_SWAP_CH3 4 | ||
| #define MIPI_SWAP_CLK 3 | ||
| /* bit[2:0] are reserved */ | ||
|
|
||
| /******** END of I2C Address 0x84 *********/ | ||
|
|
||
| /* DPCD regs */ | ||
| #define DPCD_DPCD_REV 0x00 | ||
| #define DPCD_MAX_LINK_RATE 0x01 | ||
| #define DPCD_MAX_LANE_COUNT 0x02 | ||
|
|
||
| /********* ANX7625 Register End **********/ | ||
|
|
||
| /***************** Display *****************/ | ||
| enum AudioFs { | ||
| AUDIO_FS_441K = 0x00, | ||
| AUDIO_FS_48K = 0x02, | ||
| AUDIO_FS_32K = 0x03, | ||
| AUDIO_FS_882K = 0x08, | ||
| AUDIO_FS_96K = 0x0a, | ||
| AUDIO_FS_1764K = 0x0c, | ||
| AUDIO_FS_192K = 0x0e | ||
| }; | ||
|
|
||
| enum AudioWdLen { | ||
| AUDIO_W_LEN_16_20MAX = 0x02, | ||
| AUDIO_W_LEN_18_20MAX = 0x04, | ||
| AUDIO_W_LEN_17_20MAX = 0x0c, | ||
| AUDIO_W_LEN_19_20MAX = 0x08, | ||
| AUDIO_W_LEN_20_20MAX = 0x0a, | ||
| AUDIO_W_LEN_20_24MAX = 0x03, | ||
| AUDIO_W_LEN_22_24MAX = 0x05, | ||
| AUDIO_W_LEN_21_24MAX = 0x0d, | ||
| AUDIO_W_LEN_23_24MAX = 0x09, | ||
| AUDIO_W_LEN_24_24MAX = 0x0b | ||
| }; | ||
|
|
||
| #define I2S_CH_2 0x01 | ||
| #define TDM_CH_4 0x03 | ||
| #define TDM_CH_6 0x05 | ||
| #define TDM_CH_8 0x07 | ||
|
|
||
| #define MAX_DPCD_BUFFER_SIZE 16 | ||
|
|
||
| #define ONE_BLOCK_SIZE 128 | ||
| #define FOUR_BLOCK_SIZE (128*4) | ||
|
|
||
| struct display_timing { | ||
| unsigned int pixelclock; | ||
| unsigned int hactive; | ||
| unsigned int hfront_porch; | ||
| unsigned int hback_porch; | ||
| unsigned int hsync_len; | ||
| unsigned int vactive; | ||
| unsigned int vfront_porch; | ||
| unsigned int vback_porch; | ||
| unsigned int vsync_len; | ||
| }; | ||
|
|
||
| int anx7625_dp_start(uint8_t bus, const struct edid *edid); | ||
| int anx7625_dp_get_edid(uint8_t bus, struct edid *out); | ||
| int anx7625_init(uint8_t bus); | ||
| #endif /* __ANX7625_H__ */ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,4 @@ | ||
| config DRIVERS_ASPEED_AST2050 | ||
| bool | ||
| select DRIVERS_ASPEED_AST_COMMON | ||
| select MAINBOARD_HAS_NATIVE_VGA_INIT |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,6 @@ | ||
| config DRIVERS_ASPEED_AST_COMMON | ||
| bool | ||
| select HAVE_LINEAR_FRAMEBUFFER if MAINBOARD_DO_NATIVE_VGA_INIT | ||
| select HAVE_VGA_TEXT_FRAMEBUFFER if MAINBOARD_DO_NATIVE_VGA_INIT | ||
| select VGA if VGA_TEXT_FRAMEBUFFER | ||
| select SOFTWARE_I2C if GENERIC_LINEAR_FRAMEBUFFER |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,4 @@ | ||
| ifeq ($(CONFIG_DRIVERS_ASPEED_AST_COMMON),y) | ||
| ramstage-y += ast_dp501.c ast_main.c ast_post.c | ||
| ramstage-$(CONFIG_GENERIC_LINEAR_FRAMEBUFFER) += ast_mode.c ast_i2c.c ast_mode_corebootfb.c | ||
| endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,140 @@ | ||
| /* | ||
| * Copied from Linux drivers/gpu/drm/ast/ast_mode.c | ||
| * | ||
| * Copyright 2012 Red Hat Inc. | ||
| * Parts based on xf86-video-ast | ||
| * Copyright (c) 2005 ASPEED Technology Inc. | ||
| * Copyright Dave Airlie <airlied@redhat.com> | ||
| * Copyright 2019 9Elements Agency GmbH <patrick.rudolph@9elements.com> | ||
| * | ||
| * Permission is hereby granted, free of charge, to any person obtaining a | ||
| * copy of this software and associated documentation files (the | ||
| * "Software"), to deal in the Software without restriction, including | ||
| * without limitation the rights to use, copy, modify, merge, publish, | ||
| * distribute, sub license, and/or sell copies of the Software, and to | ||
| * permit persons to whom the Software is furnished to do so, subject to | ||
| * the following conditions: | ||
| * | ||
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL | ||
| * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, | ||
| * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | ||
| * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE | ||
| * USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| * | ||
| * The above copyright notice and this permission notice (including the | ||
| * next paragraph) shall be included in all copies or substantial portions | ||
| * of the Software. | ||
| * | ||
| */ | ||
|
|
||
| #include <delay.h> | ||
| #include <device/i2c_simple.h> | ||
|
|
||
| #include "ast_drv.h" | ||
|
|
||
| static struct ast_private *ast; | ||
|
|
||
| #define _GET_INDEX_REG(x) ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, (x)) | ||
| #define ASPEED_BUS 0 | ||
|
|
||
| static int get_clock(unsigned int bus) | ||
| { | ||
| uint32_t val, val2, count, pass; | ||
|
|
||
| count = 0; | ||
| pass = 0; | ||
| val = (_GET_INDEX_REG(0x10) >> 4) & 0x01; | ||
| do { | ||
| val2 = (_GET_INDEX_REG(0x10) >> 4) & 0x01; | ||
| if (val == val2) { | ||
| pass++; | ||
| } else { | ||
| pass = 0; | ||
| val = (_GET_INDEX_REG(0x10) >> 4) & 0x01; | ||
| } | ||
| } while ((pass < 5) && (count++ < 0x10000)); | ||
|
|
||
| return val & 1 ? 1 : 0; | ||
| } | ||
|
|
||
| static int get_data(unsigned int bus) | ||
| { | ||
| uint32_t val, val2, count, pass; | ||
|
|
||
| count = 0; | ||
| pass = 0; | ||
| val = (_GET_INDEX_REG(0x20) >> 5) & 0x01; | ||
| do { | ||
| val2 = (_GET_INDEX_REG(0x20) >> 5) & 0x01; | ||
| if (val == val2) { | ||
| pass++; | ||
| } else { | ||
| pass = 0; | ||
| val = (_GET_INDEX_REG(0x20) >> 5) & 0x01; | ||
| } | ||
| } while ((pass < 5) && (count++ < 0x10000)); | ||
|
|
||
| return val & 1 ? 1 : 0; | ||
| } | ||
|
|
||
| static void set_clock(unsigned int bus, int clock) | ||
| { | ||
| int i; | ||
| u8 ujcrb7, jtemp; | ||
|
|
||
| for (i = 0; i < 0x10000; i++) { | ||
| ujcrb7 = ((clock & 0x01) ? 0 : 1); | ||
| ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0xf4, ujcrb7); | ||
| jtemp = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x01); | ||
| if (ujcrb7 == jtemp) | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| static void set_data(unsigned int bus, int data) | ||
| { | ||
| int i; | ||
| u8 ujcrb7, jtemp; | ||
|
|
||
| for (i = 0; i < 0x10000; i++) { | ||
| ujcrb7 = ((data & 0x01) ? 0 : 1) << 2; | ||
| ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0xf1, ujcrb7); | ||
| jtemp = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x04); | ||
| if (ujcrb7 == jtemp) | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| static struct software_i2c_ops ast_ops = { | ||
| .set_sda = set_data, | ||
| .set_scl = set_clock, | ||
| .get_sda = get_data, | ||
| .get_scl = get_clock, | ||
| }; | ||
|
|
||
| int ast_software_i2c_read(struct ast_private *ast_priv, uint8_t edid[128]) | ||
| { | ||
| struct software_i2c_ops *backup; | ||
| int ret; | ||
|
|
||
| backup = software_i2c[ASPEED_BUS]; | ||
|
|
||
| software_i2c[ASPEED_BUS] = &ast_ops; | ||
|
|
||
| ast = ast_priv; | ||
|
|
||
| /* Ast POST pulled SDA and SCL low, recover the bus to a known state */ | ||
| set_clock(ASPEED_BUS, 1); | ||
| set_data(ASPEED_BUS, 1); | ||
|
|
||
| udelay(100); | ||
|
|
||
| /* Need to reset internal EEPROM counter to 0 */ | ||
| ret = i2c_read_bytes(ASPEED_BUS, 0x50, 0, edid, 128); | ||
|
|
||
| software_i2c[ASPEED_BUS] = backup; | ||
|
|
||
| return ret; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,256 @@ | ||
| /* | ||
| * Copied from Linux drivers/gpu/drm/ast/ast_mode.c | ||
| * | ||
| * Copyright 2012 Red Hat Inc. | ||
| * Parts based on xf86-video-ast | ||
| * Copyright (c) 2005 ASPEED Technology Inc. | ||
| * Copyright Dave Airlie <airlied@redhat.com> | ||
| * Copyright 2019 9Elements Agency GmbH <patrick.rudolph@9elements.com> | ||
| * | ||
| * Permission is hereby granted, free of charge, to any person obtaining a | ||
| * copy of this software and associated documentation files (the | ||
| * "Software"), to deal in the Software without restriction, including | ||
| * without limitation the rights to use, copy, modify, merge, publish, | ||
| * distribute, sub license, and/or sell copies of the Software, and to | ||
| * permit persons to whom the Software is furnished to do so, subject to | ||
| * the following conditions: | ||
| * | ||
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL | ||
| * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, | ||
| * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | ||
| * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE | ||
| * USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| * | ||
| * The above copyright notice and this permission notice (including the | ||
| * next paragraph) shall be included in all copies or substantial portions | ||
| * of the Software. | ||
| * | ||
| */ | ||
|
|
||
| #include <edid.h> | ||
|
|
||
| #include "ast_drv.h" | ||
|
|
||
| /* | ||
| * Set framebuffer MMIO address, which must fall into BAR0 MMIO window. | ||
| * | ||
| * Complete reimplementation as the original expects multiple kernel internal | ||
| * subsystems to be present. | ||
| */ | ||
| int ast_crtc_do_set_base(struct drm_crtc *crtc) | ||
| { | ||
| struct ast_private *ast = crtc->dev->dev_private; | ||
| struct drm_framebuffer *fb = crtc->primary->fb; | ||
|
|
||
| /* PCI BAR 0 */ | ||
| struct resource *res = find_resource(crtc->dev->pdev, 0x10); | ||
| if (!res) { | ||
| printk(BIOS_ERR, "BAR0 resource not found.\n"); | ||
| return -EIO; | ||
| } | ||
|
|
||
| if (res->size < fb->pitches[0] * crtc->mode.vdisplay) { | ||
| dev_err(dev->pdev, "Framebuffer doesn't fit into BAR0 MMIO window\n"); | ||
| return -ENOMEM; | ||
| } | ||
|
|
||
| fb->mmio_addr = (u32)res2mmio(res, 4095, 4095); | ||
|
|
||
| ast_set_offset_reg(crtc); | ||
| ast_set_start_address_crt1(ast, fb->mmio_addr); | ||
|
|
||
| return 0; | ||
| } | ||
|
|
||
| static void ast_edid_to_drmmode(struct edid *edid, struct drm_display_mode *mode) | ||
| { | ||
| memset(mode, 0, sizeof(*mode)); | ||
|
|
||
| mode->hdisplay = edid->mode.ha; | ||
| mode->vdisplay = edid->mode.va; | ||
| mode->crtc_hdisplay = edid->mode.ha; | ||
| mode->crtc_vdisplay = edid->mode.va; | ||
|
|
||
| /* EDID clock is in 10kHz, but drm clock is in KHz */ | ||
| mode->clock = edid->mode.pixel_clock * 10; | ||
| mode->vrefresh = edid->mode.refresh; | ||
|
|
||
| mode->crtc_hblank_start = edid->mode.ha; | ||
| mode->crtc_hblank_end = edid->mode.ha + edid->mode.hbl; | ||
| mode->crtc_hsync_start = edid->mode.ha + edid->mode.hso; | ||
| mode->crtc_hsync_end = edid->mode.ha + edid->mode.hso + edid->mode.hspw; | ||
| mode->crtc_htotal = mode->crtc_hblank_end; | ||
|
|
||
| mode->crtc_vblank_start = edid->mode.va; | ||
| mode->crtc_vblank_end = edid->mode.va + edid->mode.vbl; | ||
| mode->crtc_vsync_start = edid->mode.va + edid->mode.vso; | ||
| mode->crtc_vsync_end = edid->mode.va + edid->mode.vso + edid->mode.vspw; | ||
| mode->crtc_vtotal = mode->crtc_vblank_end; | ||
|
|
||
| mode->flags = 0; | ||
| if (edid->mode.phsync == '+') | ||
| mode->flags |= DRM_MODE_FLAG_PHSYNC; | ||
| else | ||
| mode->flags |= DRM_MODE_FLAG_NHSYNC; | ||
|
|
||
| if (edid->mode.pvsync == '+') | ||
| mode->flags |= DRM_MODE_FLAG_PVSYNC; | ||
| else | ||
| mode->flags |= DRM_MODE_FLAG_NVSYNC; | ||
| } | ||
|
|
||
| static int ast_select_mode(struct drm_connector *connector, | ||
| struct edid *edid) | ||
| { | ||
| struct ast_private *ast = connector->dev->dev_private; | ||
| bool widescreen; | ||
| u8 raw[128]; | ||
| bool flags = false; | ||
|
|
||
| if (ast->tx_chip_type == AST_TX_DP501) { | ||
| ast->dp501_maxclk = 0xff; | ||
| flags = ast_dp501_read_edid(connector->dev, (u8 *)raw); | ||
| if (flags) | ||
| ast->dp501_maxclk = ast_get_dp501_max_clk(connector->dev); | ||
| else | ||
| dev_err(dev->pdev, "I2C transmission error\n"); | ||
| } | ||
|
|
||
| if (!flags) | ||
| ast_software_i2c_read(ast, raw); | ||
|
|
||
| if (decode_edid(raw, sizeof(raw), edid) != EDID_CONFORMANT) { | ||
| dev_err(dev->pdev, "Failed to decode EDID\n"); | ||
| printk(BIOS_DEBUG, "Assuming VGA for KVM\n"); | ||
|
|
||
| memset(edid, 0, sizeof(*edid)); | ||
|
|
||
| edid->mode.pixel_clock = 6411; | ||
| edid->mode.refresh = 60; | ||
| edid->mode.ha = 1024; | ||
| edid->mode.hspw = 4; | ||
| edid->mode.hso = 56; | ||
| edid->mode.hbl = 264; | ||
| edid->mode.phsync = '-'; | ||
|
|
||
| edid->mode.va = 768; | ||
| edid->mode.vspw = 3; | ||
| edid->mode.vso = 1; | ||
| edid->mode.vbl = 26; | ||
| edid->mode.pvsync = '+'; | ||
| } | ||
|
|
||
| printk(BIOS_DEBUG, "AST: Display has %dpx x %dpx\n", edid->mode.ha, edid->mode.va); | ||
|
|
||
| widescreen = !!(((edid->mode.ha * 4) % (edid->mode.va * 3))); | ||
|
|
||
| while (ast_mode_valid(connector, edid->mode.ha, edid->mode.va) != MODE_OK) { | ||
| /* Select a compatible smaller mode */ | ||
| if (edid->mode.ha > 1920 && widescreen) { | ||
| edid->mode.ha = 1920; | ||
| edid->mode.va = 1080; | ||
| } else if (edid->mode.ha >= 1920 && widescreen) { | ||
| edid->mode.ha = 1680; | ||
| edid->mode.va = 1050; | ||
| } else if (edid->mode.ha >= 1680 && widescreen) { | ||
| edid->mode.ha = 1600; | ||
| edid->mode.va = 900; | ||
| } else if (edid->mode.ha >= 1680 && !widescreen) { | ||
| edid->mode.ha = 1600; | ||
| edid->mode.va = 1200; | ||
| } else if (edid->mode.ha >= 1600 && widescreen) { | ||
| edid->mode.ha = 1440; | ||
| edid->mode.va = 900; | ||
| } else if (edid->mode.ha >= 1440 && widescreen) { | ||
| edid->mode.ha = 1360; | ||
| edid->mode.va = 768; | ||
| } else if (edid->mode.ha >= 1360 && widescreen) { | ||
| edid->mode.ha = 1280; | ||
| edid->mode.va = 800; | ||
| } else if (edid->mode.ha >= 1360 && !widescreen) { | ||
| edid->mode.ha = 1280; | ||
| edid->mode.va = 1024; | ||
| } else if (edid->mode.ha >= 1280) { | ||
| edid->mode.ha = 1024; | ||
| edid->mode.va = 768; | ||
| } else if (edid->mode.ha >= 1024) { | ||
| edid->mode.ha = 800; | ||
| edid->mode.va = 600; | ||
| } else if (edid->mode.ha >= 800) { | ||
| edid->mode.ha = 640; | ||
| edid->mode.va = 480; | ||
| } else { | ||
| dev_err(dev->pdev, "No compatible mode found.\n"); | ||
|
|
||
| return -EIO; | ||
| } | ||
| }; | ||
|
|
||
| return 0; | ||
| } | ||
|
|
||
| int ast_driver_framebuffer_init(struct drm_device *dev, int flags) | ||
| { | ||
| struct drm_display_mode adjusted_mode; | ||
| struct drm_crtc crtc; | ||
| struct drm_format format; | ||
| struct drm_primary primary; | ||
| struct drm_framebuffer fb; | ||
| struct drm_connector connector; | ||
| struct edid edid; | ||
| int ret; | ||
|
|
||
| /* Init wrapper structs */ | ||
| connector.dev = dev; | ||
|
|
||
| format.cpp[0] = 4; /* 32 BPP */ | ||
| fb.format = &format; | ||
|
|
||
| primary.fb = &fb; | ||
|
|
||
| crtc.dev = dev; | ||
| crtc.primary = &primary; | ||
|
|
||
| /* Read EDID and find mode */ | ||
| ret = ast_select_mode(&connector, &edid); | ||
| if (ret) { | ||
| dev_err(dev->pdev, "Failed to select mode.\n"); | ||
| return ret; | ||
| } | ||
|
|
||
| /* Updated edid for set_vbe_mode_info_valid */ | ||
| edid.x_resolution = edid.mode.ha; | ||
| edid.y_resolution = edid.mode.va; | ||
| edid.framebuffer_bits_per_pixel = format.cpp[0] * 8; | ||
| edid.bytes_per_line = ALIGN_UP(edid.x_resolution * format.cpp[0], 8); | ||
|
|
||
| /* Updated framebuffer info for ast_crtc_mode_set */ | ||
| fb.pitches[0] = edid.bytes_per_line; | ||
|
|
||
| printk(BIOS_DEBUG, "Using framebuffer %dpx x %dpx pitch %d @ %d BPP\n", | ||
| edid.x_resolution, edid.y_resolution, edid.bytes_per_line, | ||
| edid.framebuffer_bits_per_pixel); | ||
|
|
||
| /* Convert EDID to AST DRM mode */ | ||
| ast_edid_to_drmmode(&edid, &crtc.mode); | ||
|
|
||
| memcpy(&adjusted_mode, &crtc.mode, sizeof(crtc.mode)); | ||
|
|
||
| ret = ast_crtc_mode_set(&crtc, &crtc.mode, &adjusted_mode); | ||
| if (ret) { | ||
| dev_err(dev->pdev, "Failed to set mode.\n"); | ||
| return ret; | ||
| } | ||
|
|
||
| ast_hide_cursor(&crtc); | ||
|
|
||
| /* Advertise new mode */ | ||
| set_vbe_mode_info_valid(&edid, fb.mmio_addr); | ||
|
|
||
| /* Clear display */ | ||
| memset((void *)fb.mmio_addr, 0, edid.bytes_per_line * edid.y_resolution); | ||
|
|
||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| config DRIVERS_GENERIC_CBFS_SERIAL | ||
| bool "Serial number in CBFS" | ||
| default n | ||
| help | ||
| Enable this option to read the board serial number from a | ||
| text file located in CBFS. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| ramstage-$(CONFIG_DRIVERS_GENERIC_CBFS_SERIAL) += cbfs-serial.c |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| /* | ||
| * This file is part of the coreboot project. | ||
| * | ||
| * This program is free software; you can redistribute it and/or modify | ||
| * it under the terms of the GNU General Public License as published by | ||
| * the Free Software Foundation; version 2 of the License. | ||
| * | ||
| * This program is distributed in the hope that it will be useful, | ||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| * GNU General Public License for more details. | ||
| */ | ||
|
|
||
| #include <cbfs.h> | ||
| #include <device/device.h> | ||
| #include <smbios.h> | ||
| #include <string.h> | ||
|
|
||
|
|
||
| #define MAX_SERIAL_LENGTH 0x100 | ||
|
|
||
| const char *smbios_mainboard_serial_number(void) | ||
| { | ||
| static char serial_number[MAX_SERIAL_LENGTH + 1] = {0}; | ||
| struct cbfsf file; | ||
|
|
||
| if (serial_number[0] != 0) | ||
| return serial_number; | ||
|
|
||
| if (cbfs_boot_locate(&file, "serial_number", NULL) == 0) { | ||
| struct region_device cbfs_region; | ||
| size_t serial_len; | ||
|
|
||
| cbfs_file_data(&cbfs_region, &file); | ||
|
|
||
| serial_len = region_device_sz(&cbfs_region); | ||
| if (serial_len <= MAX_SERIAL_LENGTH) { | ||
| if (rdev_readat(&cbfs_region, serial_number, 0, | ||
| serial_len) == serial_len) { | ||
| serial_number[serial_len] = 0; | ||
| return serial_number; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| strncpy(serial_number, CONFIG_MAINBOARD_SERIAL_NUMBER, | ||
| MAX_SERIAL_LENGTH); | ||
|
|
||
| return serial_number; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,7 +19,6 @@ | |
| #include <device/pci.h> | ||
| #include <device/pci_ids.h> | ||
| #include <stdint.h> | ||
|
|
||
| #include "chip.h" | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,7 +14,6 @@ | |
| #ifndef FSP1_1_CAR_H | ||
| #define FSP1_1_CAR_H | ||
|
|
||
| #include <fsp/api.h> | ||
| #include <stdint.h> | ||
|
|
||
|
|
||