diff --git a/thermosphere/src/gpio.c b/thermosphere/src/gpio.c index e0de22df2..ea44816d9 100644 --- a/thermosphere/src/gpio.c +++ b/thermosphere/src/gpio.c @@ -16,7 +16,6 @@ #include #include -#include #include "gpio.h" #include "utils.h" diff --git a/thermosphere/src/gpio.h b/thermosphere/src/gpio.h index 38781cbc5..53560e272 100644 --- a/thermosphere/src/gpio.h +++ b/thermosphere/src/gpio.h @@ -15,7 +15,7 @@ */ #pragma once -#include "types.h" +#include #define GPIO_BASE 0x6000D000 #define MAKE_GPIO_REG(n) MAKE_REG32(GPIO_BASE + n) @@ -94,8 +94,8 @@ static inline volatile tegra_gpio_t *gpio_get_regs(void) ((TEGRA_GPIO_PORT_##port * 8) + offset) /* Mode select */ -#define GPIO_MODE_GPIO 0 -#define GPIO_MODE_SDIO 1 +#define GPIO_MODE_SFIO 0 +#define GPIO_MODE_GPIO 1 /* Direction */ #define GPIO_DIRECTION_INPUT 0 diff --git a/thermosphere/src/main.c b/thermosphere/src/main.c index 14904e167..2b1c3936f 100644 --- a/thermosphere/src/main.c +++ b/thermosphere/src/main.c @@ -4,9 +4,11 @@ int main(void) { + uart_config(UART_C); + uart_reset(UART_C); uart_init(UART_C, 115200, true); //uart_send(UART_C, "0123\n", 3); - serialLog("Hello from Thermosphere!\n"); + serialLog("Hello from Thermosphere!\r\n"); return 0; } diff --git a/thermosphere/src/pinmux.h b/thermosphere/src/pinmux.h new file mode 100644 index 000000000..2eaad0667 --- /dev/null +++ b/thermosphere/src/pinmux.h @@ -0,0 +1,208 @@ +/* + * 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 . + */ + +#pragma once + +#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; +} diff --git a/thermosphere/src/uart.c b/thermosphere/src/uart.c index 330af689d..3e83a6a8e 100644 --- a/thermosphere/src/uart.c +++ b/thermosphere/src/uart.c @@ -15,144 +15,118 @@ * along with this program. If not, see . */ -#include "timers.h" #include "uart.h" -#include "misc.h" -#include "car.h" +#include "timers.h" +#include "pinmux.h" #include "gpio.h" +#include "car.h" -static inline void uart_wait_cycles(u32 baud, u32 num) -{ - udelay((num * 1000000 + 16 * baud - 1) / (16 * baud)); -} - -static inline void uart_wait_syms(u32 baud, u32 num) -{ - udelay((num * 1000000 + baud - 1) / baud); -} - -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_set_baudrate(UartDevice dev, u32 baud) -{ - //Set baud rate. - volatile uart_t *uart = get_uart_device(dev); - - // Round to closest (hence the 8 * baud: +0.5) - u32 rate = (8 * baud + UART_CLKRATE) / (16 * baud); - - // Enable DLAB - uart->UART_LCR |= UART_LCR_DLAB; - - // Set divisor - uart->UART_THR_DLAB = (u8)rate; - uart->UART_IER_DLAB = (u8)(rate >> 8); - - // Disable DLAB - uart->UART_LCR &= ~UART_LCR_DLAB; - uart->UART_LSR; - - // Wait 2 characters worth of time - uart_wait_syms(baud, 2); -} - -void uart_flush_fifos(UartDevice dev, u32 baud, bool reset) -{ - volatile uart_t *uart = get_uart_device(dev); - - if (reset) { - uart->UART_IIR_FCR &= ~UART_FCR_FCR_EN_FIFO; - udelay(60); // From nvidia - uart->UART_IIR_FCR |= UART_FCR_TX_CLR | UART_FCR_RX_CLR; - uart->UART_IIR_FCR |= UART_FCR_FCR_EN_FIFO; - } else { - uart->UART_IIR_FCR |= UART_FCR_TX_CLR | UART_FCR_RX_CLR; +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; } - - uart->UART_LSR; - - // Erratum fix - uart_wait_cycles(baud, 32); } -void uart_init(UartDevice dev, u32 baud, bool txInverted) +void uart_reset(UartDevice dev) { - volatile uart_t *uart = get_uart_device(dev); - CarDevice uartCarDevs[] = { CARDEVICE_UARTA, CARDEVICE_UARTB, CARDEVICE_UARTC, CARDEVICE_UARTD }; if (dev == UART_C) { gpio_configure_mode(TEGRA_GPIO(G, 0), GPIO_MODE_GPIO); // Leave UART-B as GPIO - gpio_configure_mode(TEGRA_GPIO(D, 1), GPIO_MODE_SDIO); // Change UART-C to SPIO + gpio_configure_mode(TEGRA_GPIO(D, 1), GPIO_MODE_SFIO); // Change UART-C to SPIO // Fixme other uart? } - uart_select(dev); clkrst_reboot(uartCarDevs[dev]); +} +void uart_init(UartDevice dev, uint32_t baud, bool inverted) { + volatile tegra_uart_t *uart = uart_get_regs(dev); + + /* Wait for idle state. */ + uart_wait_idle(dev, UART_VENDOR_STATE_TX_IDLE); + + /* Calculate baud rate. */ + uint32_t rate = (8 * baud + 408000000) / (16 * baud); + + /* Setup UART in FIFO mode. */ + uart->UART_IER_DLAB = 0; uart->UART_MCR = 0; - uart->UART_MSR = 0; - uart->UART_RX_FIFO_CFG = 1; // Reset value - uart->UART_MIE = 0; - uart->UART_ASR = 0; - - // Enable FIFO, etc - uart->UART_IIR_FCR = UART_FCR_FCR_EN_FIFO | UART_FCR_TX_TRIG_FIFO_COUNT_GREATER_16 | UART_FCR_RX_TRIG_FIFO_COUNT_GREATER_1; - uart->UART_IRDA_CSR = txInverted ? 2 : 0; - uart->UART_LSR; - - // Erratum fix - uart_wait_cycles(baud, 3); - - // Set baud rate, etc. - uart->UART_LCR = UART_LCR_WD_LENGTH_8; - uart_set_baudrate(dev, baud); - - uart_flush_fifos(dev, baud, true); + 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. */ + uart->UART_IRDA_CSR = inverted ? 2 : 0; /* Invert TX */ + 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! -void uart_wait_idle(UartDevice dev, UartVendorStatus status) -{ - while (!(get_uart_device(dev)->UART_VENDOR_STATUS & status)); +/* This function blocks until the UART device is in the desired state. */ +void uart_wait_idle(UartDevice dev, UartVendorStatus status) { + 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); - const u8 *buf8 = (const u8 *)buf; +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); - uart->UART_THR_DLAB = buf8[i]; + 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); - u8 *buf8 = (u8 *)buf; +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); - buf8[i] = uart->UART_THR_DLAB; + while (!(uart->UART_LSR & UART_LSR_RDR)) { + /* Wait until it's possible to receive data. */ + } + *((uint8_t *)buf + i) = uart->UART_THR_DLAB; } } - -size_t uart_recv_max(UartDevice dev, void *buf, size_t maxlen) -{ - volatile uart_t *uart = get_uart_device(dev); - u8 *buf8 = (u8 *)buf; - size_t i; - - for (i = 0; i < maxlen && !(uart->UART_LSR & UART_LSR_RX_FIFO_EMPTY); i++) { - buf8[i] = uart->UART_THR_DLAB; - } - - return i; -} diff --git a/thermosphere/src/uart.h b/thermosphere/src/uart.h index 156c006ee..8550181c4 100644 --- a/thermosphere/src/uart.h +++ b/thermosphere/src/uart.h @@ -14,15 +14,16 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + #pragma once -#include "utils.h" + +#include "types.h" #define UART_BASE 0x70006000 -#define BAUD_115200 115200 -#define UART_CLKRATE 408000000 -/* Exosphère: add the clkreset values for UART C,D,E */ +#define BAUD_115200 115200 + +/* UART devices */ typedef enum { UART_A = 0, UART_B = 1, @@ -139,32 +140,30 @@ typedef enum { } UartInterruptIdentification; typedef struct { - /* 0x00 */ u32 UART_THR_DLAB; - /* 0x04 */ u32 UART_IER_DLAB; - /* 0x08 */ u32 UART_IIR_FCR; - /* 0x0C */ u32 UART_LCR; - /* 0x10 */ u32 UART_MCR; - /* 0x14 */ u32 UART_LSR; - /* 0x18 */ u32 UART_MSR; - /* 0x1C */ u32 UART_SPR; - /* 0x20 */ u32 UART_IRDA_CSR; - /* 0x24 */ u32 UART_RX_FIFO_CFG; - /* 0x28 */ u32 UART_MIE; - /* 0x2C */ u32 UART_VENDOR_STATUS; - /* 0x30 */ uint8_t _pad_30[0x0C]; - /* 0x3C */ u32 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_set_baudrate(UartDevice dev, u32 baud); -void uart_flush_fifos(UartDevice dev, u32 baud, bool reset); -void uart_init(UartDevice dev, u32 baud, bool txInverted); +void uart_config(UartDevice dev); +void uart_reset(UartDevice dev); +void uart_init(UartDevice dev, uint32_t baud, bool inverted); 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); -size_t uart_recv_max(UartDevice dev, void *buf, size_t maxlen); -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]); }