From 7cee36544cee926192516f71bfa8d7b14df3b4bb Mon Sep 17 00:00:00 2001 From: hexkyz Date: Sun, 21 Jul 2019 19:18:15 +0100 Subject: [PATCH] Cleanup and re-write uart code --- exosphere/src/bootup.c | 2 +- exosphere/src/i2c.c | 97 +++++++++----- exosphere/src/i2c.h | 38 ++++-- exosphere/src/misc.h | 11 -- exosphere/src/pinmux.h | 214 +++++++++++++++++++++++++++++++ exosphere/src/uart.c | 103 ++++++++++----- exosphere/src/uart.h | 38 +++--- exosphere/src/warmboot_main.c | 7 +- fusee/fusee-primary/src/hwinit.c | 11 +- fusee/fusee-primary/src/i2c.c | 47 ++++++- fusee/fusee-primary/src/i2c.h | 24 ++-- fusee/fusee-primary/src/uart.c | 92 +++++++++---- fusee/fusee-primary/src/uart.h | 1 + fusee/fusee-secondary/src/i2c.c | 47 ++++++- fusee/fusee-secondary/src/i2c.h | 24 ++-- sept/sept-primary/src/i2c.c | 47 ++++++- sept/sept-primary/src/i2c.h | 24 ++-- sept/sept-primary/src/pinmux.h | 211 ++++++++++++++++++++++++++++++ sept/sept-secondary/src/hwinit.c | 11 +- sept/sept-secondary/src/i2c.c | 47 ++++++- sept/sept-secondary/src/i2c.h | 24 ++-- sept/sept-secondary/src/uart.c | 92 +++++++++---- sept/sept-secondary/src/uart.h | 1 + 23 files changed, 971 insertions(+), 242 deletions(-) create mode 100644 exosphere/src/pinmux.h create mode 100644 sept/sept-primary/src/pinmux.h diff --git a/exosphere/src/bootup.c b/exosphere/src/bootup.c index b5c4b12c2..91155462c 100644 --- a/exosphere/src/bootup.c +++ b/exosphere/src/bootup.c @@ -215,7 +215,7 @@ void bootup_misc_mmio(void) { if (!g_has_booted_up) { /* N doesn't do this, but we should for compatibility. */ - uart_select(UART_A); + uart_config(UART_A); clkrst_reboot(CARDEVICE_UARTA); uart_init(UART_A, 115200); diff --git a/exosphere/src/i2c.c b/exosphere/src/i2c.c index 87c4f3b9f..319869b05 100644 --- a/exosphere/src/i2c.c +++ b/exosphere/src/i2c.c @@ -14,25 +14,56 @@ * along with this program. If not, see . */ -#include - #include "i2c.h" #include "utils.h" #include "timers.h" +#include "pinmux.h" /* Prototypes for internal commands. */ -volatile i2c_registers_t *i2c_get_registers_from_id(unsigned int id); -void i2c_load_config(volatile i2c_registers_t *regs); +volatile tegra_i2c_t *i2c_get_registers_from_id(I2CDevice id); +void i2c_load_config(volatile tegra_i2c_t *regs); -bool i2c_query(unsigned int id, uint8_t device, uint8_t r, void *dst, size_t dst_size); -bool i2c_send(unsigned int id, uint8_t device, uint8_t r, void *src, size_t src_size); +bool i2c_query(I2CDevice id, uint8_t device, uint8_t r, void *dst, size_t dst_size); +bool i2c_send(I2CDevice id, uint8_t device, uint8_t r, void *src, size_t src_size); -bool i2c_write(volatile i2c_registers_t *regs, uint8_t device, void *src, size_t src_size); -bool i2c_read(volatile i2c_registers_t *regs, uint8_t device, void *dst, size_t dst_size); +bool i2c_write(volatile tegra_i2c_t *regs, uint8_t device, void *src, size_t src_size); +bool i2c_read(volatile tegra_i2c_t *regs, uint8_t device, void *dst, size_t dst_size); + +/* Configure I2C pinmux. */ +void i2c_config(I2CDevice id) { + volatile tegra_pinmux_t *pinmux = pinmux_get_regs(); + + switch (id) { + case I2C_1: + pinmux->gen1_i2c_scl = PINMUX_INPUT; + pinmux->gen1_i2c_sda = PINMUX_INPUT; + break; + case I2C_2: + pinmux->gen2_i2c_scl = PINMUX_INPUT; + pinmux->gen2_i2c_sda = PINMUX_INPUT; + break; + case I2C_3: + pinmux->gen3_i2c_scl = PINMUX_INPUT; + pinmux->gen3_i2c_sda = PINMUX_INPUT; + break; + case I2C_4: + pinmux->cam_i2c_scl = PINMUX_INPUT; + pinmux->cam_i2c_sda = PINMUX_INPUT; + break; + case I2C_5: + pinmux->pwr_i2c_scl = PINMUX_INPUT; + pinmux->pwr_i2c_sda = PINMUX_INPUT; + break; + case I2C_6: + /* Unused. */ + break; + default: break; + } +} /* Initialize I2C based on registers. */ -void i2c_init(unsigned int id) { - volatile i2c_registers_t *regs = i2c_get_registers_from_id(id); +void i2c_init(I2CDevice id) { + volatile tegra_i2c_t *regs = i2c_get_registers_from_id(id); /* Setup divisor, and clear the bus. */ regs->I2C_I2C_CLK_DIVISOR_REGISTER_0 = 0x50001; @@ -61,16 +92,16 @@ void i2c_init(unsigned int id) { void i2c_send_pmic_cpu_shutdown_cmd(void) { uint32_t val = 0; /* PMIC == Device 4:3C. */ - i2c_query(4, 0x3C, 0x41, &val, 1); + i2c_query(I2C_5, MAX77620_PWR_I2C_ADDR, 0x41, &val, 1); val |= 4; - i2c_send(4, 0x3C, 0x41, &val, 1); + i2c_send(I2C_5, MAX77620_PWR_I2C_ADDR, 0x41, &val, 1); } /* Queries the value of TI charger bit over I2C. */ bool i2c_query_ti_charger_bit_7(void) { uint32_t val = 0; /* TI Charger = Device 0:6B. */ - i2c_query(0, 0x6B, 0, &val, 1); + i2c_query(I2C_1, BQ24193_I2C_ADDR, 0, &val, 1); return (val & 0x80) != 0; } @@ -78,34 +109,34 @@ bool i2c_query_ti_charger_bit_7(void) { void i2c_clear_ti_charger_bit_7(void) { uint32_t val = 0; /* TI Charger = Device 0:6B. */ - i2c_query(0, 0x6B, 0, &val, 1); + i2c_query(I2C_1, BQ24193_I2C_ADDR, 0, &val, 1); val &= 0x7F; - i2c_send(0, 0x6B, 0, &val, 1); + i2c_send(I2C_1, BQ24193_I2C_ADDR, 0, &val, 1); } /* Sets TI charger bit over I2C. */ void i2c_set_ti_charger_bit_7(void) { uint32_t val = 0; /* TI Charger = Device 0:6B. */ - i2c_query(0, 0x6B, 0, &val, 1); + i2c_query(I2C_1, BQ24193_I2C_ADDR, 0, &val, 1); val |= 0x80; - i2c_send(0, 0x6B, 0, &val, 1); + i2c_send(I2C_1, BQ24193_I2C_ADDR, 0, &val, 1); } /* Get registers pointer based on I2C ID. */ -volatile i2c_registers_t *i2c_get_registers_from_id(unsigned int id) { +volatile tegra_i2c_t *i2c_get_registers_from_id(I2CDevice id) { switch (id) { - case 0: + case I2C_1: return I2C1_REGS; - case 1: + case I2C_2: return I2C2_REGS; - case 2: + case I2C_3: return I2C3_REGS; - case 3: + case I2C_4: return I2C4_REGS; - case 4: + case I2C_5: return I2C5_REGS; - case 5: + case I2C_6: return I2C6_REGS; default: generic_panic(); @@ -114,7 +145,7 @@ volatile i2c_registers_t *i2c_get_registers_from_id(unsigned int id) { } /* Load hardware config for I2C4. */ -void i2c_load_config(volatile i2c_registers_t *regs) { +void i2c_load_config(volatile tegra_i2c_t *regs) { /* Set MSTR_CONFIG_LOAD, TIMEOUT_CONFIG_LOAD, undocumented bit. */ regs->I2C_I2C_CONFIG_LOAD_0 = 0x25; @@ -128,8 +159,8 @@ void i2c_load_config(volatile i2c_registers_t *regs) { } /* Reads a register from a device over I2C, writes result to output. */ -bool i2c_query(unsigned int id, uint8_t device, uint8_t r, void *dst, size_t dst_size) { - volatile i2c_registers_t *regs = i2c_get_registers_from_id(id); +bool i2c_query(I2CDevice id, uint8_t device, uint8_t r, void *dst, size_t dst_size) { + volatile tegra_i2c_t *regs = i2c_get_registers_from_id(id); uint32_t val = r; /* Write single byte register ID to device. */ @@ -145,7 +176,7 @@ bool i2c_query(unsigned int id, uint8_t device, uint8_t r, void *dst, size_t dst } /* Writes a value to a register over I2C. */ -bool i2c_send(unsigned int id, uint8_t device, uint8_t r, void *src, size_t src_size) { +bool i2c_send(I2CDevice id, uint8_t device, uint8_t r, void *src, size_t src_size) { uint32_t val = r; if (src_size == 0) { return true; @@ -158,7 +189,7 @@ bool i2c_send(unsigned int id, uint8_t device, uint8_t r, void *src, size_t src_ } /* Writes bytes to device over I2C. */ -bool i2c_write(volatile i2c_registers_t *regs, uint8_t device, void *src, size_t src_size) { +bool i2c_write(volatile tegra_i2c_t *regs, uint8_t device, void *src, size_t src_size) { if (src_size > 4) { return false; } else if (src_size == 0) { @@ -177,8 +208,7 @@ bool i2c_write(volatile i2c_registers_t *regs, uint8_t device, void *src, size_t i2c_load_config(regs); /* Config |= SEND; */ - regs->I2C_I2C_CNFG_0 |= 0x200; - + regs->I2C_I2C_CNFG_0 = ((regs->I2C_I2C_CNFG_0 & 0xFFFFFDFF) | 0x200); while (regs->I2C_I2C_STATUS_0 & 0x100) { /* Wait until not busy. */ @@ -189,7 +219,7 @@ bool i2c_write(volatile i2c_registers_t *regs, uint8_t device, void *src, size_t } /* Reads bytes from device over I2C. */ -bool i2c_read(volatile i2c_registers_t *regs, uint8_t device, void *dst, size_t dst_size) { +bool i2c_read(volatile tegra_i2c_t *regs, uint8_t device, void *dst, size_t dst_size) { if (dst_size > 4) { return false; } else if (dst_size == 0) { @@ -205,8 +235,7 @@ bool i2c_read(volatile i2c_registers_t *regs, uint8_t device, void *dst, size_t i2c_load_config(regs); /* Config |= SEND; */ - regs->I2C_I2C_CNFG_0 |= 0x200; - + regs->I2C_I2C_CNFG_0 = ((regs->I2C_I2C_CNFG_0 & 0xFFFFFDFF) | 0x200); while (regs->I2C_I2C_STATUS_0 & 0x100) { /* Wait until not busy. */ diff --git a/exosphere/src/i2c.h b/exosphere/src/i2c.h index 7369f708a..42c9afcf2 100644 --- a/exosphere/src/i2c.h +++ b/exosphere/src/i2c.h @@ -19,10 +19,27 @@ #include #include +#include #include "memory_map.h" /* Exosphere driver for the Tegra X1 I2C registers. */ +#define MAX77621_CPU_I2C_ADDR 0x1B +#define MAX77621_GPU_I2C_ADDR 0x1C +#define MAX17050_I2C_ADDR 0x36 +#define MAX77620_PWR_I2C_ADDR 0x3C +#define MAX77620_RTC_I2C_ADDR 0x68 +#define BQ24193_I2C_ADDR 0x6B + +typedef enum { + I2C_1 = 0, + I2C_2 = 1, + I2C_3 = 2, + I2C_4 = 3, + I2C_5 = 4, + I2C_6 = 5, +} I2CDevice; + typedef struct { uint32_t I2C_I2C_CNFG_0; uint32_t I2C_I2C_CMD_ADDR0_0; @@ -65,7 +82,7 @@ typedef struct { uint32_t I2C_I2C_INTERFACE_TIMING_1_0; uint32_t I2C_I2C_HS_INTERFACE_TIMING_0_0; uint32_t I2C_I2C_HS_INTERFACE_TIMING_1_0; -} i2c_registers_t; +} tegra_i2c_t; static inline uintptr_t get_i2c_dtv_234_base(void) { return MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_DTV_I2C234); @@ -75,17 +92,20 @@ static inline uintptr_t get_i2c56_spi2b_base(void) { return MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_I2C56_SPI2B); } -#define I2C1_REGS ((volatile i2c_registers_t *)(get_i2c_dtv_234_base() + 0x000)) -#define I2C2_REGS ((volatile i2c_registers_t *)(get_i2c_dtv_234_base() + 0x400)) -#define I2C3_REGS ((volatile i2c_registers_t *)(get_i2c_dtv_234_base() + 0x500)) -#define I2C4_REGS ((volatile i2c_registers_t *)(get_i2c_dtv_234_base() + 0x700)) -#define I2C5_REGS ((volatile i2c_registers_t *)(get_i2c56_spi2b_base() + 0x000)) -#define I2C6_REGS ((volatile i2c_registers_t *)(get_i2c56_spi2b_base() + 0x100)) +#define I2C1_REGS ((volatile tegra_i2c_t *)(get_i2c_dtv_234_base() + 0x000)) +#define I2C2_REGS ((volatile tegra_i2c_t *)(get_i2c_dtv_234_base() + 0x400)) +#define I2C3_REGS ((volatile tegra_i2c_t *)(get_i2c_dtv_234_base() + 0x500)) +#define I2C4_REGS ((volatile tegra_i2c_t *)(get_i2c_dtv_234_base() + 0x700)) +#define I2C5_REGS ((volatile tegra_i2c_t *)(get_i2c56_spi2b_base() + 0x000)) +#define I2C6_REGS ((volatile tegra_i2c_t *)(get_i2c56_spi2b_base() + 0x100)) -void i2c_init(unsigned int id); +void i2c_config(I2CDevice id); + +void i2c_init(I2CDevice id); +bool i2c_query(I2CDevice id, uint8_t device, uint8_t r, void *dst, size_t dst_size); +bool i2c_send(I2CDevice id, uint8_t device, uint8_t r, void *src, size_t src_size); void i2c_send_pmic_cpu_shutdown_cmd(void); - bool i2c_query_ti_charger_bit_7(void); void i2c_clear_ti_charger_bit_7(void); void i2c_set_ti_charger_bit_7(void); diff --git a/exosphere/src/misc.h b/exosphere/src/misc.h index a603a4f3b..1df69a22f 100644 --- a/exosphere/src/misc.h +++ b/exosphere/src/misc.h @@ -18,26 +18,15 @@ #define EXOSPHERE_MISC_H #include - #include "memory_map.h" /* Exosphere driver for the Tegra X1 MISC Registers. */ #define MISC_BASE (MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_MISC)) - #define MAKE_MISC_REG(n) MAKE_REG32(MISC_BASE + n) - #define APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG0_0 MAKE_MISC_REG(0x0C00) #define APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG1_0 MAKE_MISC_REG(0x0C04) #define APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG2_0 MAKE_MISC_REG(0x0C08) -#define PINMUX_AUX_GEN1_I2C_SCL_0 MAKE_MISC_REG(0x30BC) -#define PINMUX_AUX_GEN1_I2C_SDA_0 MAKE_MISC_REG(0x30C0) - -#define PINMUX_AUX_UARTn_TX_0(n) MAKE_MISC_REG(0x30E4 + 0x10 * (n)) -#define PINMUX_AUX_UARTn_RX_0(n) MAKE_MISC_REG(0x30E8 + 0x10 * (n)) -#define PINMUX_AUX_UARTn_RTS_0(n) MAKE_MISC_REG(0x30EC + 0x10 * (n)) -#define PINMUX_AUX_UARTn_CTS_0(n) MAKE_MISC_REG(0x30F0 + 0x10 * (n)) - #endif diff --git a/exosphere/src/pinmux.h b/exosphere/src/pinmux.h new file mode 100644 index 000000000..f7ee4630e --- /dev/null +++ b/exosphere/src/pinmux.h @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef EXOSPHERE_PINMUX_H +#define EXOSPHERE_PINMUX_H + +#include +#include "memory_map.h" + +#define PINMUX_BASE (MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_MISC) + 0x3000) +#define MAKE_PINMUX_REG(n) MAKE_REG32(PINMUX_BASE + n) + +#define PINMUX_TRISTATE (1 << 4) +#define PINMUX_PARKED (1 << 5) +#define PINMUX_INPUT (1 << 6) +#define PINMUX_PULL_NONE (0 << 2) +#define PINMUX_PULL_DOWN (1 << 2) +#define PINMUX_PULL_UP (2 << 2) +#define PINMUX_SELECT_FUNCTION0 0 +#define PINMUX_SELECT_FUNCTION1 1 +#define PINMUX_SELECT_FUNCTION2 2 +#define PINMUX_SELECT_FUNCTION3 3 +#define PINMUX_DRIVE_1X (0 << 13) +#define PINMUX_DRIVE_2X (1 << 13) +#define PINMUX_DRIVE_3X (2 << 13) +#define PINMUX_DRIVE_4X (3 << 13) + +typedef struct { + uint32_t sdmmc1_clk; + uint32_t sdmmc1_cmd; + uint32_t sdmmc1_dat3; + uint32_t sdmmc1_dat2; + uint32_t sdmmc1_dat1; + uint32_t sdmmc1_dat0; + uint32_t _r18; + uint32_t sdmmc3_clk; + uint32_t sdmmc3_cmd; + uint32_t sdmmc3_dat0; + uint32_t sdmmc3_dat1; + uint32_t sdmmc3_dat2; + uint32_t sdmmc3_dat3; + uint32_t _r34; + uint32_t pex_l0_rst_n; + uint32_t pex_l0_clkreq_n; + uint32_t pex_wake_n; + uint32_t pex_l1_rst_n; + uint32_t pex_l1_clkreq_n; + uint32_t sata_led_active; + uint32_t spi1_mosi; + uint32_t spi1_miso; + uint32_t spi1_sck; + uint32_t spi1_cs0; + uint32_t spi1_cs1; + uint32_t spi2_mosi; + uint32_t spi2_miso; + uint32_t spi2_sck; + uint32_t spi2_cs0; + uint32_t spi2_cs1; + uint32_t spi4_mosi; + uint32_t spi4_miso; + uint32_t spi4_sck; + uint32_t spi4_cs0; + uint32_t qspi_sck; + uint32_t qspi_cs_n; + uint32_t qspi_io0; + uint32_t qspi_io1; + uint32_t qspi_io2; + uint32_t qspi_io3; + uint32_t _ra0; + uint32_t dmic1_clk; + uint32_t dmic1_dat; + uint32_t dmic2_clk; + uint32_t dmic2_dat; + uint32_t dmic3_clk; + uint32_t dmic3_dat; + uint32_t gen1_i2c_scl; + uint32_t gen1_i2c_sda; + uint32_t gen2_i2c_scl; + uint32_t gen2_i2c_sda; + uint32_t gen3_i2c_scl; + uint32_t gen3_i2c_sda; + uint32_t cam_i2c_scl; + uint32_t cam_i2c_sda; + uint32_t pwr_i2c_scl; + uint32_t pwr_i2c_sda; + uint32_t uart1_tx; + uint32_t uart1_rx; + uint32_t uart1_rts; + uint32_t uart1_cts; + uint32_t uart2_tx; + uint32_t uart2_rx; + uint32_t uart2_rts; + uint32_t uart2_cts; + uint32_t uart3_tx; + uint32_t uart3_rx; + uint32_t uart3_rts; + uint32_t uart3_cts; + uint32_t uart4_tx; + uint32_t uart4_rx; + uint32_t uart4_rts; + uint32_t uart4_cts; + uint32_t dap1_fs; + uint32_t dap1_din; + uint32_t dap1_dout; + uint32_t dap1_sclk; + uint32_t dap2_fs; + uint32_t dap2_din; + uint32_t dap2_dout; + uint32_t dap2_sclk; + uint32_t dap4_fs; + uint32_t dap4_din; + uint32_t dap4_dout; + uint32_t dap4_sclk; + uint32_t cam1_mclk; + uint32_t cam2_mclk; + uint32_t jtag_rtck; + uint32_t clk_32k_in; + uint32_t clk_32k_out; + uint32_t batt_bcl; + uint32_t clk_req; + uint32_t cpu_pwr_req; + uint32_t pwr_int_n; + uint32_t shutdown; + uint32_t core_pwr_req; + uint32_t aud_mclk; + uint32_t dvfs_pwm; + uint32_t dvfs_clk; + uint32_t gpio_x1_aud; + uint32_t gpio_x3_aud; + uint32_t pcc7; + uint32_t hdmi_cec; + uint32_t hdmi_int_dp_hpd; + uint32_t spdif_out; + uint32_t spdif_in; + uint32_t usb_vbus_en0; + uint32_t usb_vbus_en1; + uint32_t dp_hpd0; + uint32_t wifi_en; + uint32_t wifi_rst; + uint32_t wifi_wake_ap; + uint32_t ap_wake_bt; + uint32_t bt_rst; + uint32_t bt_wake_ap; + uint32_t ap_wake_nfc; + uint32_t nfc_en; + uint32_t nfc_int; + uint32_t gps_en; + uint32_t gps_rst; + uint32_t cam_rst; + uint32_t cam_af_en; + uint32_t cam_flash_en; + uint32_t cam1_pwdn; + uint32_t cam2_pwdn; + uint32_t cam1_strobe; + uint32_t lcd_te; + uint32_t lcd_bl_pwm; + uint32_t lcd_bl_en; + uint32_t lcd_rst; + uint32_t lcd_gpio1; + uint32_t lcd_gpio2; + uint32_t ap_ready; + uint32_t touch_rst; + uint32_t touch_clk; + uint32_t modem_wake_ap; + uint32_t touch_int; + uint32_t motion_int; + uint32_t als_prox_int; + uint32_t temp_alert; + uint32_t button_power_on; + uint32_t button_vol_up; + uint32_t button_vol_down; + uint32_t button_slide_sw; + uint32_t button_home; + uint32_t pa6; + uint32_t pe6; + uint32_t pe7; + uint32_t ph6; + uint32_t pk0; + uint32_t pk1; + uint32_t pk2; + uint32_t pk3; + uint32_t pk4; + uint32_t pk5; + uint32_t pk6; + uint32_t pk7; + uint32_t pl0; + uint32_t pl1; + uint32_t pz0; + uint32_t pz1; + uint32_t pz2; + uint32_t pz3; + uint32_t pz4; + uint32_t pz5; +} tegra_pinmux_t; + +static inline volatile tegra_pinmux_t *pinmux_get_regs(void) +{ + return (volatile tegra_pinmux_t *)PINMUX_BASE; +} + +#endif diff --git a/exosphere/src/uart.c b/exosphere/src/uart.c index bb8f321bc..1ae9b99cd 100644 --- a/exosphere/src/uart.c +++ b/exosphere/src/uart.c @@ -15,66 +15,103 @@ * along with this program. If not, see . */ -#include "timers.h" #include "uart.h" -#include "misc.h" +#include "timers.h" +#include "pinmux.h" -void uart_select(UartDevice dev) { - unsigned int id = (unsigned int)dev; - PINMUX_AUX_UARTn_TX_0(id) = 0; /* UART */ - PINMUX_AUX_UARTn_RX_0(id) = 0x48; /* UART, enable, pull up */ - PINMUX_AUX_UARTn_RTS_0(id) = 0; /* UART */ - PINMUX_AUX_UARTn_CTS_0(id) = 0x44; /* UART, enable, pull down */ +void uart_config(UartDevice dev) { + volatile tegra_pinmux_t *pinmux = pinmux_get_regs(); + + switch (dev) { + case UART_A: + pinmux->uart1_rx = 0; + pinmux->uart1_tx = (PINMUX_INPUT | PINMUX_PULL_UP); + pinmux->uart1_rts = 0; + pinmux->uart1_cts = (PINMUX_INPUT | PINMUX_PULL_DOWN); + break; + case UART_B: + pinmux->uart2_rx = 0; + pinmux->uart2_tx = (PINMUX_INPUT | PINMUX_PULL_UP); + pinmux->uart2_rts = 0; + pinmux->uart2_cts = (PINMUX_INPUT | PINMUX_PULL_DOWN); + break; + case UART_C: + pinmux->uart3_rx = 0; + pinmux->uart3_tx = (PINMUX_INPUT | PINMUX_PULL_UP); + pinmux->uart3_rts = 0; + pinmux->uart3_cts = (PINMUX_INPUT | PINMUX_PULL_DOWN); + break; + case UART_D: + pinmux->uart4_rx = 0; + pinmux->uart4_tx = (PINMUX_INPUT | PINMUX_PULL_UP); + pinmux->uart4_rts = 0; + pinmux->uart4_cts = (PINMUX_INPUT | PINMUX_PULL_DOWN); + break; + case UART_E: + /* Unused. */ + break; + default: break; + } } void uart_init(UartDevice dev, uint32_t baud) { - volatile uart_t *uart = get_uart_device(dev); + volatile tegra_uart_t *uart = uart_get_regs(dev); - /* Set baud rate. */ + /* Wait for idle state. */ + uart_wait_idle(dev, UART_VENDOR_STATE_TX_IDLE); + + /* Calculate baud rate. */ uint32_t rate = (8 * baud + 408000000) / (16 * baud); - uart->UART_LCR = UART_LCR_DLAB; /* Enable DLAB. */ - uart->UART_THR_DLAB = (uint8_t)rate; /* Divisor latch LSB. */ - uart->UART_IER_DLAB = (uint8_t)(rate >> 8); /* Divisor latch MSB. */ - uart->UART_LCR = 0; /* Diable DLAB. */ - /* Setup UART in fifo mode. */ + /* Setup UART in FIFO mode. */ uart->UART_IER_DLAB = 0; - uart->UART_IIR_FCR = UART_FCR_FCR_EN_FIFO | UART_FCR_RX_CLR | UART_FCR_TX_CLR; /* Enable and clear TX and RX FIFOs. */ - uart->UART_LSR; - wait(3 * ((baud + 999999) / baud)); - uart->UART_LCR = UART_LCR_WD_LENGTH_8; /* Set word length 8. */ uart->UART_MCR = 0; - uart->UART_MSR = 0; - uart->UART_IRDA_CSR = 0; - uart->UART_RX_FIFO_CFG = 1; /* Set RX_FIFO trigger level */ - uart->UART_MIE = 0; - uart->UART_ASR = 0; + uart->UART_LCR = (UART_LCR_DLAB | UART_LCR_WD_LENGTH_8); /* Enable DLAB and set word length 8. */ + uart->UART_THR_DLAB = (uint8_t)rate; /* Divisor latch LSB. */ + uart->UART_IER_DLAB = (uint8_t)(rate >> 8); /* Divisor latch MSB. */ + uart->UART_LCR &= ~(UART_LCR_DLAB); /* Disable DLAB. */ + + /* Flush FIFO. */ + uart->UART_IIR_FCR = (UART_FCR_FCR_EN_FIFO | UART_FCR_RX_CLR | UART_FCR_TX_CLR); /* Enable and clear TX and RX FIFOs. */ + wait(3 * ((baud + 999999) / baud)); + + /* Wait for idle state. */ + uart_wait_idle(dev, UART_VENDOR_STATE_TX_IDLE | UART_VENDOR_STATE_RX_IDLE); } -/* This function blocks until the UART device (dev) is in the desired state (status). Make sure the desired state can be reached! */ +/* This function blocks until the UART device is in the desired state. */ void uart_wait_idle(UartDevice dev, UartVendorStatus status) { - while (!(get_uart_device(dev)->UART_VENDOR_STATUS & status)) { - /* Wait */ + volatile tegra_uart_t *uart = uart_get_regs(dev); + + if (status & UART_VENDOR_STATE_TX_IDLE) { + while (!(uart->UART_LSR & UART_LSR_TMTY)) { + /* Wait */ + } + } + if (status & UART_VENDOR_STATE_RX_IDLE) { + while (uart->UART_LSR & UART_LSR_RDR) { + /* Wait */ + } } } void uart_send(UartDevice dev, const void *buf, size_t len) { - volatile uart_t *uart = get_uart_device(dev); + volatile tegra_uart_t *uart = uart_get_regs(dev); for (size_t i = 0; i < len; i++) { - while (uart->UART_LSR & UART_LSR_TX_FIFO_FULL) { - /* Wait until the TX FIFO isn't full */ + while (!(uart->UART_LSR & UART_LSR_THRE)) { + /* Wait until it's possible to send data. */ } uart->UART_THR_DLAB = *((const uint8_t *)buf + i); } } void uart_recv(UartDevice dev, void *buf, size_t len) { - volatile uart_t *uart = get_uart_device(dev); + volatile tegra_uart_t *uart = uart_get_regs(dev); for (size_t i = 0; i < len; i++) { - while (uart->UART_LSR & UART_LSR_RX_FIFO_EMPTY) { - /* Wait until the RX FIFO isn't empty */ + while (!(uart->UART_LSR & UART_LSR_RDR)) { + /* Wait until it's possible to receive data. */ } *((uint8_t *)buf + i) = uart->UART_THR_DLAB; } diff --git a/exosphere/src/uart.h b/exosphere/src/uart.h index 8444bb873..d629376e1 100644 --- a/exosphere/src/uart.h +++ b/exosphere/src/uart.h @@ -31,7 +31,7 @@ static inline uintptr_t get_uart_base(void) { #define BAUD_115200 115200 -/* Exosphère: add the clkreset values for UART C,D,E */ +/* UART devices */ typedef enum { UART_A = 0, UART_B = 1, @@ -148,31 +148,31 @@ typedef enum { } UartInterruptIdentification; typedef struct { - /* 0x00 */ uint32_t UART_THR_DLAB; - /* 0x04 */ uint32_t UART_IER_DLAB; - /* 0x08 */ uint32_t UART_IIR_FCR; - /* 0x0C */ uint32_t UART_LCR; - /* 0x10 */ uint32_t UART_MCR; - /* 0x14 */ uint32_t UART_LSR; - /* 0x18 */ uint32_t UART_MSR; - /* 0x1C */ uint32_t UART_SPR; - /* 0x20 */ uint32_t UART_IRDA_CSR; - /* 0x24 */ uint32_t UART_RX_FIFO_CFG; - /* 0x28 */ uint32_t UART_MIE; - /* 0x2C */ uint32_t UART_VENDOR_STATUS; - /* 0x30 */ uint8_t _pad_30[0x0C]; - /* 0x3C */ uint32_t UART_ASR; -} uart_t; + uint32_t UART_THR_DLAB; + uint32_t UART_IER_DLAB; + uint32_t UART_IIR_FCR; + uint32_t UART_LCR; + uint32_t UART_MCR; + uint32_t UART_LSR; + uint32_t UART_MSR; + uint32_t UART_SPR; + uint32_t UART_IRDA_CSR; + uint32_t UART_RX_FIFO_CFG; + uint32_t UART_MIE; + uint32_t UART_VENDOR_STATUS; + uint8_t _0x30[0x0C]; + uint32_t UART_ASR; +} tegra_uart_t; -void uart_select(UartDevice dev); +void uart_config(UartDevice dev); void uart_init(UartDevice dev, uint32_t baud); void uart_wait_idle(UartDevice dev, UartVendorStatus status); void uart_send(UartDevice dev, const void *buf, size_t len); void uart_recv(UartDevice dev, void *buf, size_t len); -static inline volatile uart_t *get_uart_device(UartDevice dev) { +static inline volatile tegra_uart_t *uart_get_regs(UartDevice dev) { static const size_t offsets[] = {0, 0x40, 0x200, 0x300, 0x400}; - return (volatile uart_t *)(UART_BASE + offsets[dev]); + return (volatile tegra_uart_t *)(UART_BASE + offsets[dev]); } #endif diff --git a/exosphere/src/warmboot_main.c b/exosphere/src/warmboot_main.c index fbbc55c2e..cbef68a56 100644 --- a/exosphere/src/warmboot_main.c +++ b/exosphere/src/warmboot_main.c @@ -24,7 +24,6 @@ #include "bootup.h" #include "smc_api.h" #include "exocfg.h" - #include "se.h" #include "mc.h" #include "car.h" @@ -32,7 +31,6 @@ #include "misc.h" #include "uart.h" #include "interrupt.h" - #include "pmc.h" uintptr_t get_warmboot_main_stack_address(void) { @@ -41,8 +39,7 @@ uintptr_t get_warmboot_main_stack_address(void) { static void warmboot_configure_hiz_mode(void) { /* Enable input to I2C1 */ - PINMUX_AUX_GEN1_I2C_SCL_0 = 0x40; - PINMUX_AUX_GEN1_I2C_SDA_0 = 0x40; + i2c_config(I2C_1); clkrst_reboot(CARDEVICE_I2C1); i2c_init(0); @@ -69,7 +66,7 @@ void __attribute__((noreturn)) warmboot_main(void) { if (VIRT_MC_SECURITY_CFG3 == 0) { /* N only does this on dev units, but we will do it unconditionally. */ { - uart_select(UART_A); + uart_config(UART_A); clkrst_reboot(CARDEVICE_UARTA); uart_init(UART_A, 115200); } diff --git a/fusee/fusee-primary/src/hwinit.c b/fusee/fusee-primary/src/hwinit.c index e99aa3644..8e61afbf3 100644 --- a/fusee/fusee-primary/src/hwinit.c +++ b/fusee/fusee-primary/src/hwinit.c @@ -75,14 +75,9 @@ void config_gpios() gpio_configure_direction(TEGRA_GPIO(E, 6), GPIO_DIRECTION_INPUT); gpio_configure_direction(TEGRA_GPIO(H, 6), GPIO_DIRECTION_INPUT); - pinmux->gen1_i2c_scl = PINMUX_INPUT; - pinmux->gen1_i2c_sda = PINMUX_INPUT; - pinmux->pwr_i2c_scl = PINMUX_INPUT; - pinmux->pwr_i2c_sda = PINMUX_INPUT; - pinmux->uart1_rx = 0; - pinmux->uart1_tx = (PINMUX_INPUT | PINMUX_PULL_UP); - pinmux->uart1_rts = 0; - pinmux->uart1_cts = (PINMUX_INPUT | PINMUX_PULL_DOWN); + i2c_config(I2C_1); + i2c_config(I2C_5); + uart_config(UART_A); /* Configure volume up/down as inputs. */ gpio_configure_mode(GPIO_BUTTON_VOL_UP, GPIO_MODE_GPIO); diff --git a/fusee/fusee-primary/src/i2c.c b/fusee/fusee-primary/src/i2c.c index e1d15c114..b28f2d9a5 100644 --- a/fusee/fusee-primary/src/i2c.c +++ b/fusee/fusee-primary/src/i2c.c @@ -17,19 +17,52 @@ #include "i2c.h" #include "utils.h" #include "timers.h" +#include "pinmux.h" /* Prototypes for internal commands. */ -volatile tegra_i2c_t *i2c_get_registers_from_id(unsigned int id); +volatile tegra_i2c_t *i2c_get_registers_from_id(I2CDevice id); void i2c_load_config(volatile tegra_i2c_t *regs); -bool i2c_query(unsigned int id, uint8_t device, uint8_t r, void *dst, size_t dst_size); -bool i2c_send(unsigned int id, uint8_t device, uint8_t r, void *src, size_t src_size); +bool i2c_query(I2CDevice id, uint8_t device, uint8_t r, void *dst, size_t dst_size); +bool i2c_send(I2CDevice id, uint8_t device, uint8_t r, void *src, size_t src_size); bool i2c_write(volatile tegra_i2c_t *regs, uint8_t device, void *src, size_t src_size); bool i2c_read(volatile tegra_i2c_t *regs, uint8_t device, void *dst, size_t dst_size); +/* Configure I2C pinmux. */ +void i2c_config(I2CDevice id) { + volatile tegra_pinmux_t *pinmux = pinmux_get_regs(); + + switch (id) { + case I2C_1: + pinmux->gen1_i2c_scl = PINMUX_INPUT; + pinmux->gen1_i2c_sda = PINMUX_INPUT; + break; + case I2C_2: + pinmux->gen2_i2c_scl = PINMUX_INPUT; + pinmux->gen2_i2c_sda = PINMUX_INPUT; + break; + case I2C_3: + pinmux->gen3_i2c_scl = PINMUX_INPUT; + pinmux->gen3_i2c_sda = PINMUX_INPUT; + break; + case I2C_4: + pinmux->cam_i2c_scl = PINMUX_INPUT; + pinmux->cam_i2c_sda = PINMUX_INPUT; + break; + case I2C_5: + pinmux->pwr_i2c_scl = PINMUX_INPUT; + pinmux->pwr_i2c_sda = PINMUX_INPUT; + break; + case I2C_6: + /* Unused. */ + break; + default: break; + } +} + /* Initialize I2C based on registers. */ -void i2c_init(unsigned int id) { +void i2c_init(I2CDevice id) { volatile tegra_i2c_t *regs = i2c_get_registers_from_id(id); /* Setup divisor, and clear the bus. */ @@ -91,7 +124,7 @@ void i2c_set_ti_charger_bit_7(void) { } /* Get registers pointer based on I2C ID. */ -volatile tegra_i2c_t *i2c_get_registers_from_id(unsigned int id) { +volatile tegra_i2c_t *i2c_get_registers_from_id(I2CDevice id) { switch (id) { case I2C_1: return I2C1_REGS; @@ -126,7 +159,7 @@ void i2c_load_config(volatile tegra_i2c_t *regs) { } /* Reads a register from a device over I2C, writes result to output. */ -bool i2c_query(unsigned int id, uint8_t device, uint8_t r, void *dst, size_t dst_size) { +bool i2c_query(I2CDevice id, uint8_t device, uint8_t r, void *dst, size_t dst_size) { volatile tegra_i2c_t *regs = i2c_get_registers_from_id(id); uint32_t val = r; @@ -143,7 +176,7 @@ bool i2c_query(unsigned int id, uint8_t device, uint8_t r, void *dst, size_t dst } /* Writes a value to a register over I2C. */ -bool i2c_send(unsigned int id, uint8_t device, uint8_t r, void *src, size_t src_size) { +bool i2c_send(I2CDevice id, uint8_t device, uint8_t r, void *src, size_t src_size) { uint32_t val = r; if (src_size == 0) { return true; diff --git a/fusee/fusee-primary/src/i2c.h b/fusee/fusee-primary/src/i2c.h index 8fcc0f1c4..b5a5671aa 100644 --- a/fusee/fusee-primary/src/i2c.h +++ b/fusee/fusee-primary/src/i2c.h @@ -24,13 +24,6 @@ #define I2C1234_BASE 0x7000C000 #define I2C56_BASE 0x7000D000 -#define I2C_1 0 -#define I2C_2 1 -#define I2C_3 2 -#define I2C_4 3 -#define I2C_5 4 -#define I2C_6 5 - #define MAX77621_CPU_I2C_ADDR 0x1B #define MAX77621_GPU_I2C_ADDR 0x1C #define MAX17050_I2C_ADDR 0x36 @@ -38,6 +31,15 @@ #define MAX77620_RTC_I2C_ADDR 0x68 #define BQ24193_I2C_ADDR 0x6B +typedef enum { + I2C_1 = 0, + I2C_2 = 1, + I2C_3 = 2, + I2C_4 = 3, + I2C_5 = 4, + I2C_6 = 5, +} I2CDevice; + typedef struct { uint32_t I2C_I2C_CNFG_0; uint32_t I2C_I2C_CMD_ADDR0_0; @@ -89,9 +91,11 @@ typedef struct { #define I2C5_REGS ((volatile tegra_i2c_t *)(I2C56_BASE + 0x000)) #define I2C6_REGS ((volatile tegra_i2c_t *)(I2C56_BASE + 0x100)) -void i2c_init(unsigned int id); -bool i2c_query(unsigned int id, uint8_t device, uint8_t r, void *dst, size_t dst_size); -bool i2c_send(unsigned int id, uint8_t device, uint8_t r, void *src, size_t src_size); +void i2c_config(I2CDevice id); + +void i2c_init(I2CDevice id); +bool i2c_query(I2CDevice id, uint8_t device, uint8_t r, void *dst, size_t dst_size); +bool i2c_send(I2CDevice id, uint8_t device, uint8_t r, void *src, size_t src_size); void i2c_send_pmic_cpu_shutdown_cmd(void); bool i2c_query_ti_charger_bit_7(void); diff --git a/fusee/fusee-primary/src/uart.c b/fusee/fusee-primary/src/uart.c index 4004c71f3..f9024d471 100644 --- a/fusee/fusee-primary/src/uart.c +++ b/fusee/fusee-primary/src/uart.c @@ -17,35 +17,81 @@ #include "uart.h" #include "timers.h" +#include "pinmux.h" + +void uart_config(UartDevice dev) { + volatile tegra_pinmux_t *pinmux = pinmux_get_regs(); + + switch (dev) { + case UART_A: + pinmux->uart1_rx = 0; + pinmux->uart1_tx = (PINMUX_INPUT | PINMUX_PULL_UP); + pinmux->uart1_rts = 0; + pinmux->uart1_cts = (PINMUX_INPUT | PINMUX_PULL_DOWN); + break; + case UART_B: + pinmux->uart2_rx = 0; + pinmux->uart2_tx = (PINMUX_INPUT | PINMUX_PULL_UP); + pinmux->uart2_rts = 0; + pinmux->uart2_cts = (PINMUX_INPUT | PINMUX_PULL_DOWN); + break; + case UART_C: + pinmux->uart3_rx = 0; + pinmux->uart3_tx = (PINMUX_INPUT | PINMUX_PULL_UP); + pinmux->uart3_rts = 0; + pinmux->uart3_cts = (PINMUX_INPUT | PINMUX_PULL_DOWN); + break; + case UART_D: + pinmux->uart4_rx = 0; + pinmux->uart4_tx = (PINMUX_INPUT | PINMUX_PULL_UP); + pinmux->uart4_rts = 0; + pinmux->uart4_cts = (PINMUX_INPUT | PINMUX_PULL_DOWN); + break; + case UART_E: + /* Unused. */ + break; + default: break; + } +} void uart_init(UartDevice dev, uint32_t baud) { volatile tegra_uart_t *uart = uart_get_regs(dev); - /* Set baud rate. */ - uint32_t rate = (8 * baud + 408000000) / (16 * baud); - uart->UART_LCR = UART_LCR_DLAB; /* Enable DLAB. */ - uart->UART_THR_DLAB = (uint8_t)rate; /* Divisor latch LSB. */ - uart->UART_IER_DLAB = (uint8_t)(rate >> 8); /* Divisor latch MSB. */ - uart->UART_LCR = 0; /* Diable DLAB. */ + /* Wait for idle state. */ + uart_wait_idle(dev, UART_VENDOR_STATE_TX_IDLE); - /* Setup UART in fifo mode. */ + /* Calculate baud rate. */ + uint32_t rate = (8 * baud + 408000000) / (16 * baud); + + /* Setup UART in FIFO mode. */ uart->UART_IER_DLAB = 0; - uart->UART_IIR_FCR = UART_FCR_FCR_EN_FIFO | UART_FCR_RX_CLR | UART_FCR_TX_CLR; /* Enable and clear TX and RX FIFOs. */ - (void)uart->UART_LSR; - udelay(3 * ((baud + 999999) / baud)); - uart->UART_LCR = UART_LCR_WD_LENGTH_8; /* Set word length 8. */ uart->UART_MCR = 0; - uart->UART_MSR = 0; - uart->UART_IRDA_CSR = 0; - uart->UART_RX_FIFO_CFG = 1; /* Set RX_FIFO trigger level */ - uart->UART_MIE = 0; - uart->UART_ASR = 0; + uart->UART_LCR = (UART_LCR_DLAB | UART_LCR_WD_LENGTH_8); /* Enable DLAB and set word length 8. */ + uart->UART_THR_DLAB = (uint8_t)rate; /* Divisor latch LSB. */ + uart->UART_IER_DLAB = (uint8_t)(rate >> 8); /* Divisor latch MSB. */ + uart->UART_LCR &= ~(UART_LCR_DLAB); /* Disable DLAB. */ + + /* Flush FIFO. */ + uart->UART_IIR_FCR = (UART_FCR_FCR_EN_FIFO | UART_FCR_RX_CLR | UART_FCR_TX_CLR); /* Enable and clear TX and RX FIFOs. */ + udelay(3 * ((baud + 999999) / baud)); + + /* Wait for idle state. */ + uart_wait_idle(dev, UART_VENDOR_STATE_TX_IDLE | UART_VENDOR_STATE_RX_IDLE); } -/* This function blocks until the UART device (dev) is in the desired state (status). Make sure the desired state can be reached! */ +/* This function blocks until the UART device is in the desired state. */ void uart_wait_idle(UartDevice dev, UartVendorStatus status) { - while (!(uart_get_regs(dev)->UART_VENDOR_STATUS & status)) { - /* Wait */ + volatile tegra_uart_t *uart = uart_get_regs(dev); + + if (status & UART_VENDOR_STATE_TX_IDLE) { + while (!(uart->UART_LSR & UART_LSR_TMTY)) { + /* Wait */ + } + } + if (status & UART_VENDOR_STATE_RX_IDLE) { + while (uart->UART_LSR & UART_LSR_RDR) { + /* Wait */ + } } } @@ -53,8 +99,8 @@ void uart_send(UartDevice dev, const void *buf, size_t len) { volatile tegra_uart_t *uart = uart_get_regs(dev); for (size_t i = 0; i < len; i++) { - while (uart->UART_LSR & UART_LSR_TX_FIFO_FULL) { - /* Wait until the TX FIFO isn't full */ + while (!(uart->UART_LSR & UART_LSR_THRE)) { + /* Wait until it's possible to send data. */ } uart->UART_THR_DLAB = *((const uint8_t *)buf + i); } @@ -64,8 +110,8 @@ void uart_recv(UartDevice dev, void *buf, size_t len) { volatile tegra_uart_t *uart = uart_get_regs(dev); for (size_t i = 0; i < len; i++) { - while (uart->UART_LSR & UART_LSR_RX_FIFO_EMPTY) { - /* Wait until the RX FIFO isn't empty */ + while (!(uart->UART_LSR & UART_LSR_RDR)) { + /* Wait until it's possible to receive data. */ } *((uint8_t *)buf + i) = uart->UART_THR_DLAB; } diff --git a/fusee/fusee-primary/src/uart.h b/fusee/fusee-primary/src/uart.h index 99079f91a..e19c93458 100644 --- a/fusee/fusee-primary/src/uart.h +++ b/fusee/fusee-primary/src/uart.h @@ -157,6 +157,7 @@ typedef struct { uint32_t UART_ASR; } tegra_uart_t; +void uart_config(UartDevice dev); void uart_init(UartDevice dev, uint32_t baud); void uart_wait_idle(UartDevice dev, UartVendorStatus status); void uart_send(UartDevice dev, const void *buf, size_t len); diff --git a/fusee/fusee-secondary/src/i2c.c b/fusee/fusee-secondary/src/i2c.c index e1d15c114..b28f2d9a5 100644 --- a/fusee/fusee-secondary/src/i2c.c +++ b/fusee/fusee-secondary/src/i2c.c @@ -17,19 +17,52 @@ #include "i2c.h" #include "utils.h" #include "timers.h" +#include "pinmux.h" /* Prototypes for internal commands. */ -volatile tegra_i2c_t *i2c_get_registers_from_id(unsigned int id); +volatile tegra_i2c_t *i2c_get_registers_from_id(I2CDevice id); void i2c_load_config(volatile tegra_i2c_t *regs); -bool i2c_query(unsigned int id, uint8_t device, uint8_t r, void *dst, size_t dst_size); -bool i2c_send(unsigned int id, uint8_t device, uint8_t r, void *src, size_t src_size); +bool i2c_query(I2CDevice id, uint8_t device, uint8_t r, void *dst, size_t dst_size); +bool i2c_send(I2CDevice id, uint8_t device, uint8_t r, void *src, size_t src_size); bool i2c_write(volatile tegra_i2c_t *regs, uint8_t device, void *src, size_t src_size); bool i2c_read(volatile tegra_i2c_t *regs, uint8_t device, void *dst, size_t dst_size); +/* Configure I2C pinmux. */ +void i2c_config(I2CDevice id) { + volatile tegra_pinmux_t *pinmux = pinmux_get_regs(); + + switch (id) { + case I2C_1: + pinmux->gen1_i2c_scl = PINMUX_INPUT; + pinmux->gen1_i2c_sda = PINMUX_INPUT; + break; + case I2C_2: + pinmux->gen2_i2c_scl = PINMUX_INPUT; + pinmux->gen2_i2c_sda = PINMUX_INPUT; + break; + case I2C_3: + pinmux->gen3_i2c_scl = PINMUX_INPUT; + pinmux->gen3_i2c_sda = PINMUX_INPUT; + break; + case I2C_4: + pinmux->cam_i2c_scl = PINMUX_INPUT; + pinmux->cam_i2c_sda = PINMUX_INPUT; + break; + case I2C_5: + pinmux->pwr_i2c_scl = PINMUX_INPUT; + pinmux->pwr_i2c_sda = PINMUX_INPUT; + break; + case I2C_6: + /* Unused. */ + break; + default: break; + } +} + /* Initialize I2C based on registers. */ -void i2c_init(unsigned int id) { +void i2c_init(I2CDevice id) { volatile tegra_i2c_t *regs = i2c_get_registers_from_id(id); /* Setup divisor, and clear the bus. */ @@ -91,7 +124,7 @@ void i2c_set_ti_charger_bit_7(void) { } /* Get registers pointer based on I2C ID. */ -volatile tegra_i2c_t *i2c_get_registers_from_id(unsigned int id) { +volatile tegra_i2c_t *i2c_get_registers_from_id(I2CDevice id) { switch (id) { case I2C_1: return I2C1_REGS; @@ -126,7 +159,7 @@ void i2c_load_config(volatile tegra_i2c_t *regs) { } /* Reads a register from a device over I2C, writes result to output. */ -bool i2c_query(unsigned int id, uint8_t device, uint8_t r, void *dst, size_t dst_size) { +bool i2c_query(I2CDevice id, uint8_t device, uint8_t r, void *dst, size_t dst_size) { volatile tegra_i2c_t *regs = i2c_get_registers_from_id(id); uint32_t val = r; @@ -143,7 +176,7 @@ bool i2c_query(unsigned int id, uint8_t device, uint8_t r, void *dst, size_t dst } /* Writes a value to a register over I2C. */ -bool i2c_send(unsigned int id, uint8_t device, uint8_t r, void *src, size_t src_size) { +bool i2c_send(I2CDevice id, uint8_t device, uint8_t r, void *src, size_t src_size) { uint32_t val = r; if (src_size == 0) { return true; diff --git a/fusee/fusee-secondary/src/i2c.h b/fusee/fusee-secondary/src/i2c.h index 8fcc0f1c4..b5a5671aa 100644 --- a/fusee/fusee-secondary/src/i2c.h +++ b/fusee/fusee-secondary/src/i2c.h @@ -24,13 +24,6 @@ #define I2C1234_BASE 0x7000C000 #define I2C56_BASE 0x7000D000 -#define I2C_1 0 -#define I2C_2 1 -#define I2C_3 2 -#define I2C_4 3 -#define I2C_5 4 -#define I2C_6 5 - #define MAX77621_CPU_I2C_ADDR 0x1B #define MAX77621_GPU_I2C_ADDR 0x1C #define MAX17050_I2C_ADDR 0x36 @@ -38,6 +31,15 @@ #define MAX77620_RTC_I2C_ADDR 0x68 #define BQ24193_I2C_ADDR 0x6B +typedef enum { + I2C_1 = 0, + I2C_2 = 1, + I2C_3 = 2, + I2C_4 = 3, + I2C_5 = 4, + I2C_6 = 5, +} I2CDevice; + typedef struct { uint32_t I2C_I2C_CNFG_0; uint32_t I2C_I2C_CMD_ADDR0_0; @@ -89,9 +91,11 @@ typedef struct { #define I2C5_REGS ((volatile tegra_i2c_t *)(I2C56_BASE + 0x000)) #define I2C6_REGS ((volatile tegra_i2c_t *)(I2C56_BASE + 0x100)) -void i2c_init(unsigned int id); -bool i2c_query(unsigned int id, uint8_t device, uint8_t r, void *dst, size_t dst_size); -bool i2c_send(unsigned int id, uint8_t device, uint8_t r, void *src, size_t src_size); +void i2c_config(I2CDevice id); + +void i2c_init(I2CDevice id); +bool i2c_query(I2CDevice id, uint8_t device, uint8_t r, void *dst, size_t dst_size); +bool i2c_send(I2CDevice id, uint8_t device, uint8_t r, void *src, size_t src_size); void i2c_send_pmic_cpu_shutdown_cmd(void); bool i2c_query_ti_charger_bit_7(void); diff --git a/sept/sept-primary/src/i2c.c b/sept/sept-primary/src/i2c.c index e1d15c114..b28f2d9a5 100644 --- a/sept/sept-primary/src/i2c.c +++ b/sept/sept-primary/src/i2c.c @@ -17,19 +17,52 @@ #include "i2c.h" #include "utils.h" #include "timers.h" +#include "pinmux.h" /* Prototypes for internal commands. */ -volatile tegra_i2c_t *i2c_get_registers_from_id(unsigned int id); +volatile tegra_i2c_t *i2c_get_registers_from_id(I2CDevice id); void i2c_load_config(volatile tegra_i2c_t *regs); -bool i2c_query(unsigned int id, uint8_t device, uint8_t r, void *dst, size_t dst_size); -bool i2c_send(unsigned int id, uint8_t device, uint8_t r, void *src, size_t src_size); +bool i2c_query(I2CDevice id, uint8_t device, uint8_t r, void *dst, size_t dst_size); +bool i2c_send(I2CDevice id, uint8_t device, uint8_t r, void *src, size_t src_size); bool i2c_write(volatile tegra_i2c_t *regs, uint8_t device, void *src, size_t src_size); bool i2c_read(volatile tegra_i2c_t *regs, uint8_t device, void *dst, size_t dst_size); +/* Configure I2C pinmux. */ +void i2c_config(I2CDevice id) { + volatile tegra_pinmux_t *pinmux = pinmux_get_regs(); + + switch (id) { + case I2C_1: + pinmux->gen1_i2c_scl = PINMUX_INPUT; + pinmux->gen1_i2c_sda = PINMUX_INPUT; + break; + case I2C_2: + pinmux->gen2_i2c_scl = PINMUX_INPUT; + pinmux->gen2_i2c_sda = PINMUX_INPUT; + break; + case I2C_3: + pinmux->gen3_i2c_scl = PINMUX_INPUT; + pinmux->gen3_i2c_sda = PINMUX_INPUT; + break; + case I2C_4: + pinmux->cam_i2c_scl = PINMUX_INPUT; + pinmux->cam_i2c_sda = PINMUX_INPUT; + break; + case I2C_5: + pinmux->pwr_i2c_scl = PINMUX_INPUT; + pinmux->pwr_i2c_sda = PINMUX_INPUT; + break; + case I2C_6: + /* Unused. */ + break; + default: break; + } +} + /* Initialize I2C based on registers. */ -void i2c_init(unsigned int id) { +void i2c_init(I2CDevice id) { volatile tegra_i2c_t *regs = i2c_get_registers_from_id(id); /* Setup divisor, and clear the bus. */ @@ -91,7 +124,7 @@ void i2c_set_ti_charger_bit_7(void) { } /* Get registers pointer based on I2C ID. */ -volatile tegra_i2c_t *i2c_get_registers_from_id(unsigned int id) { +volatile tegra_i2c_t *i2c_get_registers_from_id(I2CDevice id) { switch (id) { case I2C_1: return I2C1_REGS; @@ -126,7 +159,7 @@ void i2c_load_config(volatile tegra_i2c_t *regs) { } /* Reads a register from a device over I2C, writes result to output. */ -bool i2c_query(unsigned int id, uint8_t device, uint8_t r, void *dst, size_t dst_size) { +bool i2c_query(I2CDevice id, uint8_t device, uint8_t r, void *dst, size_t dst_size) { volatile tegra_i2c_t *regs = i2c_get_registers_from_id(id); uint32_t val = r; @@ -143,7 +176,7 @@ bool i2c_query(unsigned int id, uint8_t device, uint8_t r, void *dst, size_t dst } /* Writes a value to a register over I2C. */ -bool i2c_send(unsigned int id, uint8_t device, uint8_t r, void *src, size_t src_size) { +bool i2c_send(I2CDevice id, uint8_t device, uint8_t r, void *src, size_t src_size) { uint32_t val = r; if (src_size == 0) { return true; diff --git a/sept/sept-primary/src/i2c.h b/sept/sept-primary/src/i2c.h index 8fcc0f1c4..b5a5671aa 100644 --- a/sept/sept-primary/src/i2c.h +++ b/sept/sept-primary/src/i2c.h @@ -24,13 +24,6 @@ #define I2C1234_BASE 0x7000C000 #define I2C56_BASE 0x7000D000 -#define I2C_1 0 -#define I2C_2 1 -#define I2C_3 2 -#define I2C_4 3 -#define I2C_5 4 -#define I2C_6 5 - #define MAX77621_CPU_I2C_ADDR 0x1B #define MAX77621_GPU_I2C_ADDR 0x1C #define MAX17050_I2C_ADDR 0x36 @@ -38,6 +31,15 @@ #define MAX77620_RTC_I2C_ADDR 0x68 #define BQ24193_I2C_ADDR 0x6B +typedef enum { + I2C_1 = 0, + I2C_2 = 1, + I2C_3 = 2, + I2C_4 = 3, + I2C_5 = 4, + I2C_6 = 5, +} I2CDevice; + typedef struct { uint32_t I2C_I2C_CNFG_0; uint32_t I2C_I2C_CMD_ADDR0_0; @@ -89,9 +91,11 @@ typedef struct { #define I2C5_REGS ((volatile tegra_i2c_t *)(I2C56_BASE + 0x000)) #define I2C6_REGS ((volatile tegra_i2c_t *)(I2C56_BASE + 0x100)) -void i2c_init(unsigned int id); -bool i2c_query(unsigned int id, uint8_t device, uint8_t r, void *dst, size_t dst_size); -bool i2c_send(unsigned int id, uint8_t device, uint8_t r, void *src, size_t src_size); +void i2c_config(I2CDevice id); + +void i2c_init(I2CDevice id); +bool i2c_query(I2CDevice id, uint8_t device, uint8_t r, void *dst, size_t dst_size); +bool i2c_send(I2CDevice id, uint8_t device, uint8_t r, void *src, size_t src_size); void i2c_send_pmic_cpu_shutdown_cmd(void); bool i2c_query_ti_charger_bit_7(void); diff --git a/sept/sept-primary/src/pinmux.h b/sept/sept-primary/src/pinmux.h new file mode 100644 index 000000000..71764c656 --- /dev/null +++ b/sept/sept-primary/src/pinmux.h @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef FUSEE_PINMUX_H +#define FUSEE_PINMUX_H + +#define PINMUX_BASE 0x70003000 +#define MAKE_PINMUX_REG(n) MAKE_REG32(PINMUX_BASE + n) + +#define PINMUX_TRISTATE (1 << 4) +#define PINMUX_PARKED (1 << 5) +#define PINMUX_INPUT (1 << 6) +#define PINMUX_PULL_NONE (0 << 2) +#define PINMUX_PULL_DOWN (1 << 2) +#define PINMUX_PULL_UP (2 << 2) +#define PINMUX_SELECT_FUNCTION0 0 +#define PINMUX_SELECT_FUNCTION1 1 +#define PINMUX_SELECT_FUNCTION2 2 +#define PINMUX_SELECT_FUNCTION3 3 +#define PINMUX_DRIVE_1X (0 << 13) +#define PINMUX_DRIVE_2X (1 << 13) +#define PINMUX_DRIVE_3X (2 << 13) +#define PINMUX_DRIVE_4X (3 << 13) + +typedef struct { + uint32_t sdmmc1_clk; + uint32_t sdmmc1_cmd; + uint32_t sdmmc1_dat3; + uint32_t sdmmc1_dat2; + uint32_t sdmmc1_dat1; + uint32_t sdmmc1_dat0; + uint32_t _r18; + uint32_t sdmmc3_clk; + uint32_t sdmmc3_cmd; + uint32_t sdmmc3_dat0; + uint32_t sdmmc3_dat1; + uint32_t sdmmc3_dat2; + uint32_t sdmmc3_dat3; + uint32_t _r34; + uint32_t pex_l0_rst_n; + uint32_t pex_l0_clkreq_n; + uint32_t pex_wake_n; + uint32_t pex_l1_rst_n; + uint32_t pex_l1_clkreq_n; + uint32_t sata_led_active; + uint32_t spi1_mosi; + uint32_t spi1_miso; + uint32_t spi1_sck; + uint32_t spi1_cs0; + uint32_t spi1_cs1; + uint32_t spi2_mosi; + uint32_t spi2_miso; + uint32_t spi2_sck; + uint32_t spi2_cs0; + uint32_t spi2_cs1; + uint32_t spi4_mosi; + uint32_t spi4_miso; + uint32_t spi4_sck; + uint32_t spi4_cs0; + uint32_t qspi_sck; + uint32_t qspi_cs_n; + uint32_t qspi_io0; + uint32_t qspi_io1; + uint32_t qspi_io2; + uint32_t qspi_io3; + uint32_t _ra0; + uint32_t dmic1_clk; + uint32_t dmic1_dat; + uint32_t dmic2_clk; + uint32_t dmic2_dat; + uint32_t dmic3_clk; + uint32_t dmic3_dat; + uint32_t gen1_i2c_scl; + uint32_t gen1_i2c_sda; + uint32_t gen2_i2c_scl; + uint32_t gen2_i2c_sda; + uint32_t gen3_i2c_scl; + uint32_t gen3_i2c_sda; + uint32_t cam_i2c_scl; + uint32_t cam_i2c_sda; + uint32_t pwr_i2c_scl; + uint32_t pwr_i2c_sda; + uint32_t uart1_tx; + uint32_t uart1_rx; + uint32_t uart1_rts; + uint32_t uart1_cts; + uint32_t uart2_tx; + uint32_t uart2_rx; + uint32_t uart2_rts; + uint32_t uart2_cts; + uint32_t uart3_tx; + uint32_t uart3_rx; + uint32_t uart3_rts; + uint32_t uart3_cts; + uint32_t uart4_tx; + uint32_t uart4_rx; + uint32_t uart4_rts; + uint32_t uart4_cts; + uint32_t dap1_fs; + uint32_t dap1_din; + uint32_t dap1_dout; + uint32_t dap1_sclk; + uint32_t dap2_fs; + uint32_t dap2_din; + uint32_t dap2_dout; + uint32_t dap2_sclk; + uint32_t dap4_fs; + uint32_t dap4_din; + uint32_t dap4_dout; + uint32_t dap4_sclk; + uint32_t cam1_mclk; + uint32_t cam2_mclk; + uint32_t jtag_rtck; + uint32_t clk_32k_in; + uint32_t clk_32k_out; + uint32_t batt_bcl; + uint32_t clk_req; + uint32_t cpu_pwr_req; + uint32_t pwr_int_n; + uint32_t shutdown; + uint32_t core_pwr_req; + uint32_t aud_mclk; + uint32_t dvfs_pwm; + uint32_t dvfs_clk; + uint32_t gpio_x1_aud; + uint32_t gpio_x3_aud; + uint32_t pcc7; + uint32_t hdmi_cec; + uint32_t hdmi_int_dp_hpd; + uint32_t spdif_out; + uint32_t spdif_in; + uint32_t usb_vbus_en0; + uint32_t usb_vbus_en1; + uint32_t dp_hpd0; + uint32_t wifi_en; + uint32_t wifi_rst; + uint32_t wifi_wake_ap; + uint32_t ap_wake_bt; + uint32_t bt_rst; + uint32_t bt_wake_ap; + uint32_t ap_wake_nfc; + uint32_t nfc_en; + uint32_t nfc_int; + uint32_t gps_en; + uint32_t gps_rst; + uint32_t cam_rst; + uint32_t cam_af_en; + uint32_t cam_flash_en; + uint32_t cam1_pwdn; + uint32_t cam2_pwdn; + uint32_t cam1_strobe; + uint32_t lcd_te; + uint32_t lcd_bl_pwm; + uint32_t lcd_bl_en; + uint32_t lcd_rst; + uint32_t lcd_gpio1; + uint32_t lcd_gpio2; + uint32_t ap_ready; + uint32_t touch_rst; + uint32_t touch_clk; + uint32_t modem_wake_ap; + uint32_t touch_int; + uint32_t motion_int; + uint32_t als_prox_int; + uint32_t temp_alert; + uint32_t button_power_on; + uint32_t button_vol_up; + uint32_t button_vol_down; + uint32_t button_slide_sw; + uint32_t button_home; + uint32_t pa6; + uint32_t pe6; + uint32_t pe7; + uint32_t ph6; + uint32_t pk0; + uint32_t pk1; + uint32_t pk2; + uint32_t pk3; + uint32_t pk4; + uint32_t pk5; + uint32_t pk6; + uint32_t pk7; + uint32_t pl0; + uint32_t pl1; + uint32_t pz0; + uint32_t pz1; + uint32_t pz2; + uint32_t pz3; + uint32_t pz4; + uint32_t pz5; +} tegra_pinmux_t; + +static inline volatile tegra_pinmux_t *pinmux_get_regs(void) +{ + return (volatile tegra_pinmux_t *)PINMUX_BASE; +} + +#endif diff --git a/sept/sept-secondary/src/hwinit.c b/sept/sept-secondary/src/hwinit.c index e99aa3644..8e61afbf3 100644 --- a/sept/sept-secondary/src/hwinit.c +++ b/sept/sept-secondary/src/hwinit.c @@ -75,14 +75,9 @@ void config_gpios() gpio_configure_direction(TEGRA_GPIO(E, 6), GPIO_DIRECTION_INPUT); gpio_configure_direction(TEGRA_GPIO(H, 6), GPIO_DIRECTION_INPUT); - pinmux->gen1_i2c_scl = PINMUX_INPUT; - pinmux->gen1_i2c_sda = PINMUX_INPUT; - pinmux->pwr_i2c_scl = PINMUX_INPUT; - pinmux->pwr_i2c_sda = PINMUX_INPUT; - pinmux->uart1_rx = 0; - pinmux->uart1_tx = (PINMUX_INPUT | PINMUX_PULL_UP); - pinmux->uart1_rts = 0; - pinmux->uart1_cts = (PINMUX_INPUT | PINMUX_PULL_DOWN); + i2c_config(I2C_1); + i2c_config(I2C_5); + uart_config(UART_A); /* Configure volume up/down as inputs. */ gpio_configure_mode(GPIO_BUTTON_VOL_UP, GPIO_MODE_GPIO); diff --git a/sept/sept-secondary/src/i2c.c b/sept/sept-secondary/src/i2c.c index e1d15c114..b28f2d9a5 100644 --- a/sept/sept-secondary/src/i2c.c +++ b/sept/sept-secondary/src/i2c.c @@ -17,19 +17,52 @@ #include "i2c.h" #include "utils.h" #include "timers.h" +#include "pinmux.h" /* Prototypes for internal commands. */ -volatile tegra_i2c_t *i2c_get_registers_from_id(unsigned int id); +volatile tegra_i2c_t *i2c_get_registers_from_id(I2CDevice id); void i2c_load_config(volatile tegra_i2c_t *regs); -bool i2c_query(unsigned int id, uint8_t device, uint8_t r, void *dst, size_t dst_size); -bool i2c_send(unsigned int id, uint8_t device, uint8_t r, void *src, size_t src_size); +bool i2c_query(I2CDevice id, uint8_t device, uint8_t r, void *dst, size_t dst_size); +bool i2c_send(I2CDevice id, uint8_t device, uint8_t r, void *src, size_t src_size); bool i2c_write(volatile tegra_i2c_t *regs, uint8_t device, void *src, size_t src_size); bool i2c_read(volatile tegra_i2c_t *regs, uint8_t device, void *dst, size_t dst_size); +/* Configure I2C pinmux. */ +void i2c_config(I2CDevice id) { + volatile tegra_pinmux_t *pinmux = pinmux_get_regs(); + + switch (id) { + case I2C_1: + pinmux->gen1_i2c_scl = PINMUX_INPUT; + pinmux->gen1_i2c_sda = PINMUX_INPUT; + break; + case I2C_2: + pinmux->gen2_i2c_scl = PINMUX_INPUT; + pinmux->gen2_i2c_sda = PINMUX_INPUT; + break; + case I2C_3: + pinmux->gen3_i2c_scl = PINMUX_INPUT; + pinmux->gen3_i2c_sda = PINMUX_INPUT; + break; + case I2C_4: + pinmux->cam_i2c_scl = PINMUX_INPUT; + pinmux->cam_i2c_sda = PINMUX_INPUT; + break; + case I2C_5: + pinmux->pwr_i2c_scl = PINMUX_INPUT; + pinmux->pwr_i2c_sda = PINMUX_INPUT; + break; + case I2C_6: + /* Unused. */ + break; + default: break; + } +} + /* Initialize I2C based on registers. */ -void i2c_init(unsigned int id) { +void i2c_init(I2CDevice id) { volatile tegra_i2c_t *regs = i2c_get_registers_from_id(id); /* Setup divisor, and clear the bus. */ @@ -91,7 +124,7 @@ void i2c_set_ti_charger_bit_7(void) { } /* Get registers pointer based on I2C ID. */ -volatile tegra_i2c_t *i2c_get_registers_from_id(unsigned int id) { +volatile tegra_i2c_t *i2c_get_registers_from_id(I2CDevice id) { switch (id) { case I2C_1: return I2C1_REGS; @@ -126,7 +159,7 @@ void i2c_load_config(volatile tegra_i2c_t *regs) { } /* Reads a register from a device over I2C, writes result to output. */ -bool i2c_query(unsigned int id, uint8_t device, uint8_t r, void *dst, size_t dst_size) { +bool i2c_query(I2CDevice id, uint8_t device, uint8_t r, void *dst, size_t dst_size) { volatile tegra_i2c_t *regs = i2c_get_registers_from_id(id); uint32_t val = r; @@ -143,7 +176,7 @@ bool i2c_query(unsigned int id, uint8_t device, uint8_t r, void *dst, size_t dst } /* Writes a value to a register over I2C. */ -bool i2c_send(unsigned int id, uint8_t device, uint8_t r, void *src, size_t src_size) { +bool i2c_send(I2CDevice id, uint8_t device, uint8_t r, void *src, size_t src_size) { uint32_t val = r; if (src_size == 0) { return true; diff --git a/sept/sept-secondary/src/i2c.h b/sept/sept-secondary/src/i2c.h index 8fcc0f1c4..b5a5671aa 100644 --- a/sept/sept-secondary/src/i2c.h +++ b/sept/sept-secondary/src/i2c.h @@ -24,13 +24,6 @@ #define I2C1234_BASE 0x7000C000 #define I2C56_BASE 0x7000D000 -#define I2C_1 0 -#define I2C_2 1 -#define I2C_3 2 -#define I2C_4 3 -#define I2C_5 4 -#define I2C_6 5 - #define MAX77621_CPU_I2C_ADDR 0x1B #define MAX77621_GPU_I2C_ADDR 0x1C #define MAX17050_I2C_ADDR 0x36 @@ -38,6 +31,15 @@ #define MAX77620_RTC_I2C_ADDR 0x68 #define BQ24193_I2C_ADDR 0x6B +typedef enum { + I2C_1 = 0, + I2C_2 = 1, + I2C_3 = 2, + I2C_4 = 3, + I2C_5 = 4, + I2C_6 = 5, +} I2CDevice; + typedef struct { uint32_t I2C_I2C_CNFG_0; uint32_t I2C_I2C_CMD_ADDR0_0; @@ -89,9 +91,11 @@ typedef struct { #define I2C5_REGS ((volatile tegra_i2c_t *)(I2C56_BASE + 0x000)) #define I2C6_REGS ((volatile tegra_i2c_t *)(I2C56_BASE + 0x100)) -void i2c_init(unsigned int id); -bool i2c_query(unsigned int id, uint8_t device, uint8_t r, void *dst, size_t dst_size); -bool i2c_send(unsigned int id, uint8_t device, uint8_t r, void *src, size_t src_size); +void i2c_config(I2CDevice id); + +void i2c_init(I2CDevice id); +bool i2c_query(I2CDevice id, uint8_t device, uint8_t r, void *dst, size_t dst_size); +bool i2c_send(I2CDevice id, uint8_t device, uint8_t r, void *src, size_t src_size); void i2c_send_pmic_cpu_shutdown_cmd(void); bool i2c_query_ti_charger_bit_7(void); diff --git a/sept/sept-secondary/src/uart.c b/sept/sept-secondary/src/uart.c index 4004c71f3..f9024d471 100644 --- a/sept/sept-secondary/src/uart.c +++ b/sept/sept-secondary/src/uart.c @@ -17,35 +17,81 @@ #include "uart.h" #include "timers.h" +#include "pinmux.h" + +void uart_config(UartDevice dev) { + volatile tegra_pinmux_t *pinmux = pinmux_get_regs(); + + switch (dev) { + case UART_A: + pinmux->uart1_rx = 0; + pinmux->uart1_tx = (PINMUX_INPUT | PINMUX_PULL_UP); + pinmux->uart1_rts = 0; + pinmux->uart1_cts = (PINMUX_INPUT | PINMUX_PULL_DOWN); + break; + case UART_B: + pinmux->uart2_rx = 0; + pinmux->uart2_tx = (PINMUX_INPUT | PINMUX_PULL_UP); + pinmux->uart2_rts = 0; + pinmux->uart2_cts = (PINMUX_INPUT | PINMUX_PULL_DOWN); + break; + case UART_C: + pinmux->uart3_rx = 0; + pinmux->uart3_tx = (PINMUX_INPUT | PINMUX_PULL_UP); + pinmux->uart3_rts = 0; + pinmux->uart3_cts = (PINMUX_INPUT | PINMUX_PULL_DOWN); + break; + case UART_D: + pinmux->uart4_rx = 0; + pinmux->uart4_tx = (PINMUX_INPUT | PINMUX_PULL_UP); + pinmux->uart4_rts = 0; + pinmux->uart4_cts = (PINMUX_INPUT | PINMUX_PULL_DOWN); + break; + case UART_E: + /* Unused. */ + break; + default: break; + } +} void uart_init(UartDevice dev, uint32_t baud) { volatile tegra_uart_t *uart = uart_get_regs(dev); - /* Set baud rate. */ - uint32_t rate = (8 * baud + 408000000) / (16 * baud); - uart->UART_LCR = UART_LCR_DLAB; /* Enable DLAB. */ - uart->UART_THR_DLAB = (uint8_t)rate; /* Divisor latch LSB. */ - uart->UART_IER_DLAB = (uint8_t)(rate >> 8); /* Divisor latch MSB. */ - uart->UART_LCR = 0; /* Diable DLAB. */ + /* Wait for idle state. */ + uart_wait_idle(dev, UART_VENDOR_STATE_TX_IDLE); - /* Setup UART in fifo mode. */ + /* Calculate baud rate. */ + uint32_t rate = (8 * baud + 408000000) / (16 * baud); + + /* Setup UART in FIFO mode. */ uart->UART_IER_DLAB = 0; - uart->UART_IIR_FCR = UART_FCR_FCR_EN_FIFO | UART_FCR_RX_CLR | UART_FCR_TX_CLR; /* Enable and clear TX and RX FIFOs. */ - (void)uart->UART_LSR; - udelay(3 * ((baud + 999999) / baud)); - uart->UART_LCR = UART_LCR_WD_LENGTH_8; /* Set word length 8. */ uart->UART_MCR = 0; - uart->UART_MSR = 0; - uart->UART_IRDA_CSR = 0; - uart->UART_RX_FIFO_CFG = 1; /* Set RX_FIFO trigger level */ - uart->UART_MIE = 0; - uart->UART_ASR = 0; + uart->UART_LCR = (UART_LCR_DLAB | UART_LCR_WD_LENGTH_8); /* Enable DLAB and set word length 8. */ + uart->UART_THR_DLAB = (uint8_t)rate; /* Divisor latch LSB. */ + uart->UART_IER_DLAB = (uint8_t)(rate >> 8); /* Divisor latch MSB. */ + uart->UART_LCR &= ~(UART_LCR_DLAB); /* Disable DLAB. */ + + /* Flush FIFO. */ + uart->UART_IIR_FCR = (UART_FCR_FCR_EN_FIFO | UART_FCR_RX_CLR | UART_FCR_TX_CLR); /* Enable and clear TX and RX FIFOs. */ + udelay(3 * ((baud + 999999) / baud)); + + /* Wait for idle state. */ + uart_wait_idle(dev, UART_VENDOR_STATE_TX_IDLE | UART_VENDOR_STATE_RX_IDLE); } -/* This function blocks until the UART device (dev) is in the desired state (status). Make sure the desired state can be reached! */ +/* This function blocks until the UART device is in the desired state. */ void uart_wait_idle(UartDevice dev, UartVendorStatus status) { - while (!(uart_get_regs(dev)->UART_VENDOR_STATUS & status)) { - /* Wait */ + volatile tegra_uart_t *uart = uart_get_regs(dev); + + if (status & UART_VENDOR_STATE_TX_IDLE) { + while (!(uart->UART_LSR & UART_LSR_TMTY)) { + /* Wait */ + } + } + if (status & UART_VENDOR_STATE_RX_IDLE) { + while (uart->UART_LSR & UART_LSR_RDR) { + /* Wait */ + } } } @@ -53,8 +99,8 @@ void uart_send(UartDevice dev, const void *buf, size_t len) { volatile tegra_uart_t *uart = uart_get_regs(dev); for (size_t i = 0; i < len; i++) { - while (uart->UART_LSR & UART_LSR_TX_FIFO_FULL) { - /* Wait until the TX FIFO isn't full */ + while (!(uart->UART_LSR & UART_LSR_THRE)) { + /* Wait until it's possible to send data. */ } uart->UART_THR_DLAB = *((const uint8_t *)buf + i); } @@ -64,8 +110,8 @@ void uart_recv(UartDevice dev, void *buf, size_t len) { volatile tegra_uart_t *uart = uart_get_regs(dev); for (size_t i = 0; i < len; i++) { - while (uart->UART_LSR & UART_LSR_RX_FIFO_EMPTY) { - /* Wait until the RX FIFO isn't empty */ + while (!(uart->UART_LSR & UART_LSR_RDR)) { + /* Wait until it's possible to receive data. */ } *((uint8_t *)buf + i) = uart->UART_THR_DLAB; } diff --git a/sept/sept-secondary/src/uart.h b/sept/sept-secondary/src/uart.h index 99079f91a..e19c93458 100644 --- a/sept/sept-secondary/src/uart.h +++ b/sept/sept-secondary/src/uart.h @@ -157,6 +157,7 @@ typedef struct { uint32_t UART_ASR; } tegra_uart_t; +void uart_config(UartDevice dev); void uart_init(UartDevice dev, uint32_t baud); void uart_wait_idle(UartDevice dev, UartVendorStatus status); void uart_send(UartDevice dev, const void *buf, size_t len);