mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 12:21:18 +00:00
Cleanup and re-write uart code
This commit is contained in:
parent
f9c1d5fc1b
commit
7cee36544c
23 changed files with 971 additions and 242 deletions
|
@ -215,7 +215,7 @@ void bootup_misc_mmio(void) {
|
||||||
|
|
||||||
if (!g_has_booted_up) {
|
if (!g_has_booted_up) {
|
||||||
/* N doesn't do this, but we should for compatibility. */
|
/* N doesn't do this, but we should for compatibility. */
|
||||||
uart_select(UART_A);
|
uart_config(UART_A);
|
||||||
clkrst_reboot(CARDEVICE_UARTA);
|
clkrst_reboot(CARDEVICE_UARTA);
|
||||||
uart_init(UART_A, 115200);
|
uart_init(UART_A, 115200);
|
||||||
|
|
||||||
|
|
|
@ -14,25 +14,56 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "i2c.h"
|
#include "i2c.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "timers.h"
|
#include "timers.h"
|
||||||
|
#include "pinmux.h"
|
||||||
|
|
||||||
/* Prototypes for internal commands. */
|
/* Prototypes for internal commands. */
|
||||||
volatile i2c_registers_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 i2c_registers_t *regs);
|
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_query(I2CDevice 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_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_write(volatile tegra_i2c_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_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. */
|
/* Initialize I2C based on registers. */
|
||||||
void i2c_init(unsigned int id) {
|
void i2c_init(I2CDevice id) {
|
||||||
volatile i2c_registers_t *regs = i2c_get_registers_from_id(id);
|
volatile tegra_i2c_t *regs = i2c_get_registers_from_id(id);
|
||||||
|
|
||||||
/* Setup divisor, and clear the bus. */
|
/* Setup divisor, and clear the bus. */
|
||||||
regs->I2C_I2C_CLK_DIVISOR_REGISTER_0 = 0x50001;
|
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) {
|
void i2c_send_pmic_cpu_shutdown_cmd(void) {
|
||||||
uint32_t val = 0;
|
uint32_t val = 0;
|
||||||
/* PMIC == Device 4:3C. */
|
/* PMIC == Device 4:3C. */
|
||||||
i2c_query(4, 0x3C, 0x41, &val, 1);
|
i2c_query(I2C_5, MAX77620_PWR_I2C_ADDR, 0x41, &val, 1);
|
||||||
val |= 4;
|
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. */
|
/* Queries the value of TI charger bit over I2C. */
|
||||||
bool i2c_query_ti_charger_bit_7(void) {
|
bool i2c_query_ti_charger_bit_7(void) {
|
||||||
uint32_t val = 0;
|
uint32_t val = 0;
|
||||||
/* TI Charger = Device 0:6B. */
|
/* 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;
|
return (val & 0x80) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,34 +109,34 @@ bool i2c_query_ti_charger_bit_7(void) {
|
||||||
void i2c_clear_ti_charger_bit_7(void) {
|
void i2c_clear_ti_charger_bit_7(void) {
|
||||||
uint32_t val = 0;
|
uint32_t val = 0;
|
||||||
/* TI Charger = Device 0:6B. */
|
/* TI Charger = Device 0:6B. */
|
||||||
i2c_query(0, 0x6B, 0, &val, 1);
|
i2c_query(I2C_1, BQ24193_I2C_ADDR, 0, &val, 1);
|
||||||
val &= 0x7F;
|
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. */
|
/* Sets TI charger bit over I2C. */
|
||||||
void i2c_set_ti_charger_bit_7(void) {
|
void i2c_set_ti_charger_bit_7(void) {
|
||||||
uint32_t val = 0;
|
uint32_t val = 0;
|
||||||
/* TI Charger = Device 0:6B. */
|
/* TI Charger = Device 0:6B. */
|
||||||
i2c_query(0, 0x6B, 0, &val, 1);
|
i2c_query(I2C_1, BQ24193_I2C_ADDR, 0, &val, 1);
|
||||||
val |= 0x80;
|
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. */
|
/* 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) {
|
switch (id) {
|
||||||
case 0:
|
case I2C_1:
|
||||||
return I2C1_REGS;
|
return I2C1_REGS;
|
||||||
case 1:
|
case I2C_2:
|
||||||
return I2C2_REGS;
|
return I2C2_REGS;
|
||||||
case 2:
|
case I2C_3:
|
||||||
return I2C3_REGS;
|
return I2C3_REGS;
|
||||||
case 3:
|
case I2C_4:
|
||||||
return I2C4_REGS;
|
return I2C4_REGS;
|
||||||
case 4:
|
case I2C_5:
|
||||||
return I2C5_REGS;
|
return I2C5_REGS;
|
||||||
case 5:
|
case I2C_6:
|
||||||
return I2C6_REGS;
|
return I2C6_REGS;
|
||||||
default:
|
default:
|
||||||
generic_panic();
|
generic_panic();
|
||||||
|
@ -114,7 +145,7 @@ volatile i2c_registers_t *i2c_get_registers_from_id(unsigned int id) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Load hardware config for I2C4. */
|
/* 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. */
|
/* Set MSTR_CONFIG_LOAD, TIMEOUT_CONFIG_LOAD, undocumented bit. */
|
||||||
regs->I2C_I2C_CONFIG_LOAD_0 = 0x25;
|
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. */
|
/* 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 i2c_registers_t *regs = i2c_get_registers_from_id(id);
|
volatile tegra_i2c_t *regs = i2c_get_registers_from_id(id);
|
||||||
uint32_t val = r;
|
uint32_t val = r;
|
||||||
|
|
||||||
/* Write single byte register ID to device. */
|
/* 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. */
|
/* 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;
|
uint32_t val = r;
|
||||||
if (src_size == 0) {
|
if (src_size == 0) {
|
||||||
return true;
|
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. */
|
/* 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) {
|
if (src_size > 4) {
|
||||||
return false;
|
return false;
|
||||||
} else if (src_size == 0) {
|
} 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);
|
i2c_load_config(regs);
|
||||||
|
|
||||||
/* Config |= SEND; */
|
/* 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) {
|
while (regs->I2C_I2C_STATUS_0 & 0x100) {
|
||||||
/* Wait until not busy. */
|
/* 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. */
|
/* 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) {
|
if (dst_size > 4) {
|
||||||
return false;
|
return false;
|
||||||
} else if (dst_size == 0) {
|
} 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);
|
i2c_load_config(regs);
|
||||||
|
|
||||||
/* Config |= SEND; */
|
/* 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) {
|
while (regs->I2C_I2C_STATUS_0 & 0x100) {
|
||||||
/* Wait until not busy. */
|
/* Wait until not busy. */
|
||||||
|
|
|
@ -19,10 +19,27 @@
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
#include "memory_map.h"
|
#include "memory_map.h"
|
||||||
|
|
||||||
/* Exosphere driver for the Tegra X1 I2C registers. */
|
/* 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 {
|
typedef struct {
|
||||||
uint32_t I2C_I2C_CNFG_0;
|
uint32_t I2C_I2C_CNFG_0;
|
||||||
uint32_t I2C_I2C_CMD_ADDR0_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_INTERFACE_TIMING_1_0;
|
||||||
uint32_t I2C_I2C_HS_INTERFACE_TIMING_0_0;
|
uint32_t I2C_I2C_HS_INTERFACE_TIMING_0_0;
|
||||||
uint32_t I2C_I2C_HS_INTERFACE_TIMING_1_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) {
|
static inline uintptr_t get_i2c_dtv_234_base(void) {
|
||||||
return MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_DTV_I2C234);
|
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);
|
return MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_I2C56_SPI2B);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define I2C1_REGS ((volatile i2c_registers_t *)(get_i2c_dtv_234_base() + 0x000))
|
#define I2C1_REGS ((volatile tegra_i2c_t *)(get_i2c_dtv_234_base() + 0x000))
|
||||||
#define I2C2_REGS ((volatile i2c_registers_t *)(get_i2c_dtv_234_base() + 0x400))
|
#define I2C2_REGS ((volatile tegra_i2c_t *)(get_i2c_dtv_234_base() + 0x400))
|
||||||
#define I2C3_REGS ((volatile i2c_registers_t *)(get_i2c_dtv_234_base() + 0x500))
|
#define I2C3_REGS ((volatile tegra_i2c_t *)(get_i2c_dtv_234_base() + 0x500))
|
||||||
#define I2C4_REGS ((volatile i2c_registers_t *)(get_i2c_dtv_234_base() + 0x700))
|
#define I2C4_REGS ((volatile tegra_i2c_t *)(get_i2c_dtv_234_base() + 0x700))
|
||||||
#define I2C5_REGS ((volatile i2c_registers_t *)(get_i2c56_spi2b_base() + 0x000))
|
#define I2C5_REGS ((volatile tegra_i2c_t *)(get_i2c56_spi2b_base() + 0x000))
|
||||||
#define I2C6_REGS ((volatile i2c_registers_t *)(get_i2c56_spi2b_base() + 0x100))
|
#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);
|
void i2c_send_pmic_cpu_shutdown_cmd(void);
|
||||||
|
|
||||||
bool i2c_query_ti_charger_bit_7(void);
|
bool i2c_query_ti_charger_bit_7(void);
|
||||||
void i2c_clear_ti_charger_bit_7(void);
|
void i2c_clear_ti_charger_bit_7(void);
|
||||||
void i2c_set_ti_charger_bit_7(void);
|
void i2c_set_ti_charger_bit_7(void);
|
||||||
|
|
|
@ -18,26 +18,15 @@
|
||||||
#define EXOSPHERE_MISC_H
|
#define EXOSPHERE_MISC_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "memory_map.h"
|
#include "memory_map.h"
|
||||||
|
|
||||||
/* Exosphere driver for the Tegra X1 MISC Registers. */
|
/* Exosphere driver for the Tegra X1 MISC Registers. */
|
||||||
|
|
||||||
#define MISC_BASE (MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_MISC))
|
#define MISC_BASE (MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_MISC))
|
||||||
|
|
||||||
#define MAKE_MISC_REG(n) MAKE_REG32(MISC_BASE + n)
|
#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_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_REG1_0 MAKE_MISC_REG(0x0C04)
|
||||||
#define APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG2_0 MAKE_MISC_REG(0x0C08)
|
#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
|
#endif
|
||||||
|
|
214
exosphere/src/pinmux.h
Normal file
214
exosphere/src/pinmux.h
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef EXOSPHERE_PINMUX_H
|
||||||
|
#define EXOSPHERE_PINMUX_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#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
|
|
@ -15,66 +15,103 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "timers.h"
|
|
||||||
#include "uart.h"
|
#include "uart.h"
|
||||||
#include "misc.h"
|
#include "timers.h"
|
||||||
|
#include "pinmux.h"
|
||||||
|
|
||||||
void uart_select(UartDevice dev) {
|
void uart_config(UartDevice dev) {
|
||||||
unsigned int id = (unsigned int)dev;
|
volatile tegra_pinmux_t *pinmux = pinmux_get_regs();
|
||||||
PINMUX_AUX_UARTn_TX_0(id) = 0; /* UART */
|
|
||||||
PINMUX_AUX_UARTn_RX_0(id) = 0x48; /* UART, enable, pull up */
|
switch (dev) {
|
||||||
PINMUX_AUX_UARTn_RTS_0(id) = 0; /* UART */
|
case UART_A:
|
||||||
PINMUX_AUX_UARTn_CTS_0(id) = 0x44; /* UART, enable, pull down */
|
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) {
|
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);
|
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_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_MCR = 0;
|
||||||
uart->UART_MSR = 0;
|
uart->UART_LCR = (UART_LCR_DLAB | UART_LCR_WD_LENGTH_8); /* Enable DLAB and set word length 8. */
|
||||||
uart->UART_IRDA_CSR = 0;
|
uart->UART_THR_DLAB = (uint8_t)rate; /* Divisor latch LSB. */
|
||||||
uart->UART_RX_FIFO_CFG = 1; /* Set RX_FIFO trigger level */
|
uart->UART_IER_DLAB = (uint8_t)(rate >> 8); /* Divisor latch MSB. */
|
||||||
uart->UART_MIE = 0;
|
uart->UART_LCR &= ~(UART_LCR_DLAB); /* Disable DLAB. */
|
||||||
uart->UART_ASR = 0;
|
|
||||||
|
/* 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) {
|
void uart_wait_idle(UartDevice dev, UartVendorStatus status) {
|
||||||
while (!(get_uart_device(dev)->UART_VENDOR_STATUS & status)) {
|
volatile tegra_uart_t *uart = uart_get_regs(dev);
|
||||||
/* Wait */
|
|
||||||
|
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) {
|
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++) {
|
for (size_t i = 0; i < len; i++) {
|
||||||
while (uart->UART_LSR & UART_LSR_TX_FIFO_FULL) {
|
while (!(uart->UART_LSR & UART_LSR_THRE)) {
|
||||||
/* Wait until the TX FIFO isn't full */
|
/* Wait until it's possible to send data. */
|
||||||
}
|
}
|
||||||
uart->UART_THR_DLAB = *((const uint8_t *)buf + i);
|
uart->UART_THR_DLAB = *((const uint8_t *)buf + i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void uart_recv(UartDevice dev, void *buf, size_t len) {
|
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++) {
|
for (size_t i = 0; i < len; i++) {
|
||||||
while (uart->UART_LSR & UART_LSR_RX_FIFO_EMPTY) {
|
while (!(uart->UART_LSR & UART_LSR_RDR)) {
|
||||||
/* Wait until the RX FIFO isn't empty */
|
/* Wait until it's possible to receive data. */
|
||||||
}
|
}
|
||||||
*((uint8_t *)buf + i) = uart->UART_THR_DLAB;
|
*((uint8_t *)buf + i) = uart->UART_THR_DLAB;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ static inline uintptr_t get_uart_base(void) {
|
||||||
|
|
||||||
#define BAUD_115200 115200
|
#define BAUD_115200 115200
|
||||||
|
|
||||||
/* Exosphère: add the clkreset values for UART C,D,E */
|
/* UART devices */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
UART_A = 0,
|
UART_A = 0,
|
||||||
UART_B = 1,
|
UART_B = 1,
|
||||||
|
@ -148,31 +148,31 @@ typedef enum {
|
||||||
} UartInterruptIdentification;
|
} UartInterruptIdentification;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/* 0x00 */ uint32_t UART_THR_DLAB;
|
uint32_t UART_THR_DLAB;
|
||||||
/* 0x04 */ uint32_t UART_IER_DLAB;
|
uint32_t UART_IER_DLAB;
|
||||||
/* 0x08 */ uint32_t UART_IIR_FCR;
|
uint32_t UART_IIR_FCR;
|
||||||
/* 0x0C */ uint32_t UART_LCR;
|
uint32_t UART_LCR;
|
||||||
/* 0x10 */ uint32_t UART_MCR;
|
uint32_t UART_MCR;
|
||||||
/* 0x14 */ uint32_t UART_LSR;
|
uint32_t UART_LSR;
|
||||||
/* 0x18 */ uint32_t UART_MSR;
|
uint32_t UART_MSR;
|
||||||
/* 0x1C */ uint32_t UART_SPR;
|
uint32_t UART_SPR;
|
||||||
/* 0x20 */ uint32_t UART_IRDA_CSR;
|
uint32_t UART_IRDA_CSR;
|
||||||
/* 0x24 */ uint32_t UART_RX_FIFO_CFG;
|
uint32_t UART_RX_FIFO_CFG;
|
||||||
/* 0x28 */ uint32_t UART_MIE;
|
uint32_t UART_MIE;
|
||||||
/* 0x2C */ uint32_t UART_VENDOR_STATUS;
|
uint32_t UART_VENDOR_STATUS;
|
||||||
/* 0x30 */ uint8_t _pad_30[0x0C];
|
uint8_t _0x30[0x0C];
|
||||||
/* 0x3C */ uint32_t UART_ASR;
|
uint32_t UART_ASR;
|
||||||
} uart_t;
|
} tegra_uart_t;
|
||||||
|
|
||||||
void uart_select(UartDevice dev);
|
void uart_config(UartDevice dev);
|
||||||
void uart_init(UartDevice dev, uint32_t baud);
|
void uart_init(UartDevice dev, uint32_t baud);
|
||||||
void uart_wait_idle(UartDevice dev, UartVendorStatus status);
|
void uart_wait_idle(UartDevice dev, UartVendorStatus status);
|
||||||
void uart_send(UartDevice dev, const void *buf, size_t len);
|
void uart_send(UartDevice dev, const void *buf, size_t len);
|
||||||
void uart_recv(UartDevice dev, 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};
|
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
|
#endif
|
||||||
|
|
|
@ -24,7 +24,6 @@
|
||||||
#include "bootup.h"
|
#include "bootup.h"
|
||||||
#include "smc_api.h"
|
#include "smc_api.h"
|
||||||
#include "exocfg.h"
|
#include "exocfg.h"
|
||||||
|
|
||||||
#include "se.h"
|
#include "se.h"
|
||||||
#include "mc.h"
|
#include "mc.h"
|
||||||
#include "car.h"
|
#include "car.h"
|
||||||
|
@ -32,7 +31,6 @@
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
#include "uart.h"
|
#include "uart.h"
|
||||||
#include "interrupt.h"
|
#include "interrupt.h"
|
||||||
|
|
||||||
#include "pmc.h"
|
#include "pmc.h"
|
||||||
|
|
||||||
uintptr_t get_warmboot_main_stack_address(void) {
|
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) {
|
static void warmboot_configure_hiz_mode(void) {
|
||||||
/* Enable input to I2C1 */
|
/* Enable input to I2C1 */
|
||||||
PINMUX_AUX_GEN1_I2C_SCL_0 = 0x40;
|
i2c_config(I2C_1);
|
||||||
PINMUX_AUX_GEN1_I2C_SDA_0 = 0x40;
|
|
||||||
|
|
||||||
clkrst_reboot(CARDEVICE_I2C1);
|
clkrst_reboot(CARDEVICE_I2C1);
|
||||||
i2c_init(0);
|
i2c_init(0);
|
||||||
|
@ -69,7 +66,7 @@ void __attribute__((noreturn)) warmboot_main(void) {
|
||||||
if (VIRT_MC_SECURITY_CFG3 == 0) {
|
if (VIRT_MC_SECURITY_CFG3 == 0) {
|
||||||
/* N only does this on dev units, but we will do it unconditionally. */
|
/* 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);
|
clkrst_reboot(CARDEVICE_UARTA);
|
||||||
uart_init(UART_A, 115200);
|
uart_init(UART_A, 115200);
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,14 +75,9 @@ void config_gpios()
|
||||||
gpio_configure_direction(TEGRA_GPIO(E, 6), GPIO_DIRECTION_INPUT);
|
gpio_configure_direction(TEGRA_GPIO(E, 6), GPIO_DIRECTION_INPUT);
|
||||||
gpio_configure_direction(TEGRA_GPIO(H, 6), GPIO_DIRECTION_INPUT);
|
gpio_configure_direction(TEGRA_GPIO(H, 6), GPIO_DIRECTION_INPUT);
|
||||||
|
|
||||||
pinmux->gen1_i2c_scl = PINMUX_INPUT;
|
i2c_config(I2C_1);
|
||||||
pinmux->gen1_i2c_sda = PINMUX_INPUT;
|
i2c_config(I2C_5);
|
||||||
pinmux->pwr_i2c_scl = PINMUX_INPUT;
|
uart_config(UART_A);
|
||||||
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);
|
|
||||||
|
|
||||||
/* Configure volume up/down as inputs. */
|
/* Configure volume up/down as inputs. */
|
||||||
gpio_configure_mode(GPIO_BUTTON_VOL_UP, GPIO_MODE_GPIO);
|
gpio_configure_mode(GPIO_BUTTON_VOL_UP, GPIO_MODE_GPIO);
|
||||||
|
|
|
@ -17,19 +17,52 @@
|
||||||
#include "i2c.h"
|
#include "i2c.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "timers.h"
|
#include "timers.h"
|
||||||
|
#include "pinmux.h"
|
||||||
|
|
||||||
/* Prototypes for internal commands. */
|
/* 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);
|
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_query(I2CDevice 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_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_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);
|
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. */
|
/* 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);
|
volatile tegra_i2c_t *regs = i2c_get_registers_from_id(id);
|
||||||
|
|
||||||
/* Setup divisor, and clear the bus. */
|
/* 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. */
|
/* 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) {
|
switch (id) {
|
||||||
case I2C_1:
|
case I2C_1:
|
||||||
return I2C1_REGS;
|
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. */
|
/* 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);
|
volatile tegra_i2c_t *regs = i2c_get_registers_from_id(id);
|
||||||
uint32_t val = r;
|
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. */
|
/* 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;
|
uint32_t val = r;
|
||||||
if (src_size == 0) {
|
if (src_size == 0) {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -24,13 +24,6 @@
|
||||||
#define I2C1234_BASE 0x7000C000
|
#define I2C1234_BASE 0x7000C000
|
||||||
#define I2C56_BASE 0x7000D000
|
#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_CPU_I2C_ADDR 0x1B
|
||||||
#define MAX77621_GPU_I2C_ADDR 0x1C
|
#define MAX77621_GPU_I2C_ADDR 0x1C
|
||||||
#define MAX17050_I2C_ADDR 0x36
|
#define MAX17050_I2C_ADDR 0x36
|
||||||
|
@ -38,6 +31,15 @@
|
||||||
#define MAX77620_RTC_I2C_ADDR 0x68
|
#define MAX77620_RTC_I2C_ADDR 0x68
|
||||||
#define BQ24193_I2C_ADDR 0x6B
|
#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 {
|
typedef struct {
|
||||||
uint32_t I2C_I2C_CNFG_0;
|
uint32_t I2C_I2C_CNFG_0;
|
||||||
uint32_t I2C_I2C_CMD_ADDR0_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 I2C5_REGS ((volatile tegra_i2c_t *)(I2C56_BASE + 0x000))
|
||||||
#define I2C6_REGS ((volatile tegra_i2c_t *)(I2C56_BASE + 0x100))
|
#define I2C6_REGS ((volatile tegra_i2c_t *)(I2C56_BASE + 0x100))
|
||||||
|
|
||||||
void i2c_init(unsigned int id);
|
void i2c_config(I2CDevice 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_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);
|
void i2c_send_pmic_cpu_shutdown_cmd(void);
|
||||||
bool i2c_query_ti_charger_bit_7(void);
|
bool i2c_query_ti_charger_bit_7(void);
|
||||||
|
|
|
@ -17,35 +17,81 @@
|
||||||
|
|
||||||
#include "uart.h"
|
#include "uart.h"
|
||||||
#include "timers.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) {
|
void uart_init(UartDevice dev, uint32_t baud) {
|
||||||
volatile tegra_uart_t *uart = uart_get_regs(dev);
|
volatile tegra_uart_t *uart = uart_get_regs(dev);
|
||||||
|
|
||||||
/* Set baud rate. */
|
/* Wait for idle state. */
|
||||||
uint32_t rate = (8 * baud + 408000000) / (16 * baud);
|
uart_wait_idle(dev, UART_VENDOR_STATE_TX_IDLE);
|
||||||
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. */
|
/* Calculate baud rate. */
|
||||||
|
uint32_t rate = (8 * baud + 408000000) / (16 * baud);
|
||||||
|
|
||||||
|
/* Setup UART in FIFO mode. */
|
||||||
uart->UART_IER_DLAB = 0;
|
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_MCR = 0;
|
||||||
uart->UART_MSR = 0;
|
uart->UART_LCR = (UART_LCR_DLAB | UART_LCR_WD_LENGTH_8); /* Enable DLAB and set word length 8. */
|
||||||
uart->UART_IRDA_CSR = 0;
|
uart->UART_THR_DLAB = (uint8_t)rate; /* Divisor latch LSB. */
|
||||||
uart->UART_RX_FIFO_CFG = 1; /* Set RX_FIFO trigger level */
|
uart->UART_IER_DLAB = (uint8_t)(rate >> 8); /* Divisor latch MSB. */
|
||||||
uart->UART_MIE = 0;
|
uart->UART_LCR &= ~(UART_LCR_DLAB); /* Disable DLAB. */
|
||||||
uart->UART_ASR = 0;
|
|
||||||
|
/* 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) {
|
void uart_wait_idle(UartDevice dev, UartVendorStatus status) {
|
||||||
while (!(uart_get_regs(dev)->UART_VENDOR_STATUS & status)) {
|
volatile tegra_uart_t *uart = uart_get_regs(dev);
|
||||||
/* Wait */
|
|
||||||
|
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);
|
volatile tegra_uart_t *uart = uart_get_regs(dev);
|
||||||
|
|
||||||
for (size_t i = 0; i < len; i++) {
|
for (size_t i = 0; i < len; i++) {
|
||||||
while (uart->UART_LSR & UART_LSR_TX_FIFO_FULL) {
|
while (!(uart->UART_LSR & UART_LSR_THRE)) {
|
||||||
/* Wait until the TX FIFO isn't full */
|
/* Wait until it's possible to send data. */
|
||||||
}
|
}
|
||||||
uart->UART_THR_DLAB = *((const uint8_t *)buf + i);
|
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);
|
volatile tegra_uart_t *uart = uart_get_regs(dev);
|
||||||
|
|
||||||
for (size_t i = 0; i < len; i++) {
|
for (size_t i = 0; i < len; i++) {
|
||||||
while (uart->UART_LSR & UART_LSR_RX_FIFO_EMPTY) {
|
while (!(uart->UART_LSR & UART_LSR_RDR)) {
|
||||||
/* Wait until the RX FIFO isn't empty */
|
/* Wait until it's possible to receive data. */
|
||||||
}
|
}
|
||||||
*((uint8_t *)buf + i) = uart->UART_THR_DLAB;
|
*((uint8_t *)buf + i) = uart->UART_THR_DLAB;
|
||||||
}
|
}
|
||||||
|
|
|
@ -157,6 +157,7 @@ typedef struct {
|
||||||
uint32_t UART_ASR;
|
uint32_t UART_ASR;
|
||||||
} tegra_uart_t;
|
} tegra_uart_t;
|
||||||
|
|
||||||
|
void uart_config(UartDevice dev);
|
||||||
void uart_init(UartDevice dev, uint32_t baud);
|
void uart_init(UartDevice dev, uint32_t baud);
|
||||||
void uart_wait_idle(UartDevice dev, UartVendorStatus status);
|
void uart_wait_idle(UartDevice dev, UartVendorStatus status);
|
||||||
void uart_send(UartDevice dev, const void *buf, size_t len);
|
void uart_send(UartDevice dev, const void *buf, size_t len);
|
||||||
|
|
|
@ -17,19 +17,52 @@
|
||||||
#include "i2c.h"
|
#include "i2c.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "timers.h"
|
#include "timers.h"
|
||||||
|
#include "pinmux.h"
|
||||||
|
|
||||||
/* Prototypes for internal commands. */
|
/* 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);
|
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_query(I2CDevice 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_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_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);
|
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. */
|
/* 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);
|
volatile tegra_i2c_t *regs = i2c_get_registers_from_id(id);
|
||||||
|
|
||||||
/* Setup divisor, and clear the bus. */
|
/* 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. */
|
/* 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) {
|
switch (id) {
|
||||||
case I2C_1:
|
case I2C_1:
|
||||||
return I2C1_REGS;
|
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. */
|
/* 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);
|
volatile tegra_i2c_t *regs = i2c_get_registers_from_id(id);
|
||||||
uint32_t val = r;
|
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. */
|
/* 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;
|
uint32_t val = r;
|
||||||
if (src_size == 0) {
|
if (src_size == 0) {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -24,13 +24,6 @@
|
||||||
#define I2C1234_BASE 0x7000C000
|
#define I2C1234_BASE 0x7000C000
|
||||||
#define I2C56_BASE 0x7000D000
|
#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_CPU_I2C_ADDR 0x1B
|
||||||
#define MAX77621_GPU_I2C_ADDR 0x1C
|
#define MAX77621_GPU_I2C_ADDR 0x1C
|
||||||
#define MAX17050_I2C_ADDR 0x36
|
#define MAX17050_I2C_ADDR 0x36
|
||||||
|
@ -38,6 +31,15 @@
|
||||||
#define MAX77620_RTC_I2C_ADDR 0x68
|
#define MAX77620_RTC_I2C_ADDR 0x68
|
||||||
#define BQ24193_I2C_ADDR 0x6B
|
#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 {
|
typedef struct {
|
||||||
uint32_t I2C_I2C_CNFG_0;
|
uint32_t I2C_I2C_CNFG_0;
|
||||||
uint32_t I2C_I2C_CMD_ADDR0_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 I2C5_REGS ((volatile tegra_i2c_t *)(I2C56_BASE + 0x000))
|
||||||
#define I2C6_REGS ((volatile tegra_i2c_t *)(I2C56_BASE + 0x100))
|
#define I2C6_REGS ((volatile tegra_i2c_t *)(I2C56_BASE + 0x100))
|
||||||
|
|
||||||
void i2c_init(unsigned int id);
|
void i2c_config(I2CDevice 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_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);
|
void i2c_send_pmic_cpu_shutdown_cmd(void);
|
||||||
bool i2c_query_ti_charger_bit_7(void);
|
bool i2c_query_ti_charger_bit_7(void);
|
||||||
|
|
|
@ -17,19 +17,52 @@
|
||||||
#include "i2c.h"
|
#include "i2c.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "timers.h"
|
#include "timers.h"
|
||||||
|
#include "pinmux.h"
|
||||||
|
|
||||||
/* Prototypes for internal commands. */
|
/* 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);
|
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_query(I2CDevice 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_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_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);
|
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. */
|
/* 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);
|
volatile tegra_i2c_t *regs = i2c_get_registers_from_id(id);
|
||||||
|
|
||||||
/* Setup divisor, and clear the bus. */
|
/* 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. */
|
/* 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) {
|
switch (id) {
|
||||||
case I2C_1:
|
case I2C_1:
|
||||||
return I2C1_REGS;
|
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. */
|
/* 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);
|
volatile tegra_i2c_t *regs = i2c_get_registers_from_id(id);
|
||||||
uint32_t val = r;
|
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. */
|
/* 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;
|
uint32_t val = r;
|
||||||
if (src_size == 0) {
|
if (src_size == 0) {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -24,13 +24,6 @@
|
||||||
#define I2C1234_BASE 0x7000C000
|
#define I2C1234_BASE 0x7000C000
|
||||||
#define I2C56_BASE 0x7000D000
|
#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_CPU_I2C_ADDR 0x1B
|
||||||
#define MAX77621_GPU_I2C_ADDR 0x1C
|
#define MAX77621_GPU_I2C_ADDR 0x1C
|
||||||
#define MAX17050_I2C_ADDR 0x36
|
#define MAX17050_I2C_ADDR 0x36
|
||||||
|
@ -38,6 +31,15 @@
|
||||||
#define MAX77620_RTC_I2C_ADDR 0x68
|
#define MAX77620_RTC_I2C_ADDR 0x68
|
||||||
#define BQ24193_I2C_ADDR 0x6B
|
#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 {
|
typedef struct {
|
||||||
uint32_t I2C_I2C_CNFG_0;
|
uint32_t I2C_I2C_CNFG_0;
|
||||||
uint32_t I2C_I2C_CMD_ADDR0_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 I2C5_REGS ((volatile tegra_i2c_t *)(I2C56_BASE + 0x000))
|
||||||
#define I2C6_REGS ((volatile tegra_i2c_t *)(I2C56_BASE + 0x100))
|
#define I2C6_REGS ((volatile tegra_i2c_t *)(I2C56_BASE + 0x100))
|
||||||
|
|
||||||
void i2c_init(unsigned int id);
|
void i2c_config(I2CDevice 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_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);
|
void i2c_send_pmic_cpu_shutdown_cmd(void);
|
||||||
bool i2c_query_ti_charger_bit_7(void);
|
bool i2c_query_ti_charger_bit_7(void);
|
||||||
|
|
211
sept/sept-primary/src/pinmux.h
Normal file
211
sept/sept-primary/src/pinmux.h
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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
|
|
@ -75,14 +75,9 @@ void config_gpios()
|
||||||
gpio_configure_direction(TEGRA_GPIO(E, 6), GPIO_DIRECTION_INPUT);
|
gpio_configure_direction(TEGRA_GPIO(E, 6), GPIO_DIRECTION_INPUT);
|
||||||
gpio_configure_direction(TEGRA_GPIO(H, 6), GPIO_DIRECTION_INPUT);
|
gpio_configure_direction(TEGRA_GPIO(H, 6), GPIO_DIRECTION_INPUT);
|
||||||
|
|
||||||
pinmux->gen1_i2c_scl = PINMUX_INPUT;
|
i2c_config(I2C_1);
|
||||||
pinmux->gen1_i2c_sda = PINMUX_INPUT;
|
i2c_config(I2C_5);
|
||||||
pinmux->pwr_i2c_scl = PINMUX_INPUT;
|
uart_config(UART_A);
|
||||||
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);
|
|
||||||
|
|
||||||
/* Configure volume up/down as inputs. */
|
/* Configure volume up/down as inputs. */
|
||||||
gpio_configure_mode(GPIO_BUTTON_VOL_UP, GPIO_MODE_GPIO);
|
gpio_configure_mode(GPIO_BUTTON_VOL_UP, GPIO_MODE_GPIO);
|
||||||
|
|
|
@ -17,19 +17,52 @@
|
||||||
#include "i2c.h"
|
#include "i2c.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "timers.h"
|
#include "timers.h"
|
||||||
|
#include "pinmux.h"
|
||||||
|
|
||||||
/* Prototypes for internal commands. */
|
/* 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);
|
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_query(I2CDevice 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_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_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);
|
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. */
|
/* 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);
|
volatile tegra_i2c_t *regs = i2c_get_registers_from_id(id);
|
||||||
|
|
||||||
/* Setup divisor, and clear the bus. */
|
/* 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. */
|
/* 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) {
|
switch (id) {
|
||||||
case I2C_1:
|
case I2C_1:
|
||||||
return I2C1_REGS;
|
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. */
|
/* 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);
|
volatile tegra_i2c_t *regs = i2c_get_registers_from_id(id);
|
||||||
uint32_t val = r;
|
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. */
|
/* 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;
|
uint32_t val = r;
|
||||||
if (src_size == 0) {
|
if (src_size == 0) {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -24,13 +24,6 @@
|
||||||
#define I2C1234_BASE 0x7000C000
|
#define I2C1234_BASE 0x7000C000
|
||||||
#define I2C56_BASE 0x7000D000
|
#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_CPU_I2C_ADDR 0x1B
|
||||||
#define MAX77621_GPU_I2C_ADDR 0x1C
|
#define MAX77621_GPU_I2C_ADDR 0x1C
|
||||||
#define MAX17050_I2C_ADDR 0x36
|
#define MAX17050_I2C_ADDR 0x36
|
||||||
|
@ -38,6 +31,15 @@
|
||||||
#define MAX77620_RTC_I2C_ADDR 0x68
|
#define MAX77620_RTC_I2C_ADDR 0x68
|
||||||
#define BQ24193_I2C_ADDR 0x6B
|
#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 {
|
typedef struct {
|
||||||
uint32_t I2C_I2C_CNFG_0;
|
uint32_t I2C_I2C_CNFG_0;
|
||||||
uint32_t I2C_I2C_CMD_ADDR0_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 I2C5_REGS ((volatile tegra_i2c_t *)(I2C56_BASE + 0x000))
|
||||||
#define I2C6_REGS ((volatile tegra_i2c_t *)(I2C56_BASE + 0x100))
|
#define I2C6_REGS ((volatile tegra_i2c_t *)(I2C56_BASE + 0x100))
|
||||||
|
|
||||||
void i2c_init(unsigned int id);
|
void i2c_config(I2CDevice 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_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);
|
void i2c_send_pmic_cpu_shutdown_cmd(void);
|
||||||
bool i2c_query_ti_charger_bit_7(void);
|
bool i2c_query_ti_charger_bit_7(void);
|
||||||
|
|
|
@ -17,35 +17,81 @@
|
||||||
|
|
||||||
#include "uart.h"
|
#include "uart.h"
|
||||||
#include "timers.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) {
|
void uart_init(UartDevice dev, uint32_t baud) {
|
||||||
volatile tegra_uart_t *uart = uart_get_regs(dev);
|
volatile tegra_uart_t *uart = uart_get_regs(dev);
|
||||||
|
|
||||||
/* Set baud rate. */
|
/* Wait for idle state. */
|
||||||
uint32_t rate = (8 * baud + 408000000) / (16 * baud);
|
uart_wait_idle(dev, UART_VENDOR_STATE_TX_IDLE);
|
||||||
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. */
|
/* Calculate baud rate. */
|
||||||
|
uint32_t rate = (8 * baud + 408000000) / (16 * baud);
|
||||||
|
|
||||||
|
/* Setup UART in FIFO mode. */
|
||||||
uart->UART_IER_DLAB = 0;
|
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_MCR = 0;
|
||||||
uart->UART_MSR = 0;
|
uart->UART_LCR = (UART_LCR_DLAB | UART_LCR_WD_LENGTH_8); /* Enable DLAB and set word length 8. */
|
||||||
uart->UART_IRDA_CSR = 0;
|
uart->UART_THR_DLAB = (uint8_t)rate; /* Divisor latch LSB. */
|
||||||
uart->UART_RX_FIFO_CFG = 1; /* Set RX_FIFO trigger level */
|
uart->UART_IER_DLAB = (uint8_t)(rate >> 8); /* Divisor latch MSB. */
|
||||||
uart->UART_MIE = 0;
|
uart->UART_LCR &= ~(UART_LCR_DLAB); /* Disable DLAB. */
|
||||||
uart->UART_ASR = 0;
|
|
||||||
|
/* 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) {
|
void uart_wait_idle(UartDevice dev, UartVendorStatus status) {
|
||||||
while (!(uart_get_regs(dev)->UART_VENDOR_STATUS & status)) {
|
volatile tegra_uart_t *uart = uart_get_regs(dev);
|
||||||
/* Wait */
|
|
||||||
|
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);
|
volatile tegra_uart_t *uart = uart_get_regs(dev);
|
||||||
|
|
||||||
for (size_t i = 0; i < len; i++) {
|
for (size_t i = 0; i < len; i++) {
|
||||||
while (uart->UART_LSR & UART_LSR_TX_FIFO_FULL) {
|
while (!(uart->UART_LSR & UART_LSR_THRE)) {
|
||||||
/* Wait until the TX FIFO isn't full */
|
/* Wait until it's possible to send data. */
|
||||||
}
|
}
|
||||||
uart->UART_THR_DLAB = *((const uint8_t *)buf + i);
|
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);
|
volatile tegra_uart_t *uart = uart_get_regs(dev);
|
||||||
|
|
||||||
for (size_t i = 0; i < len; i++) {
|
for (size_t i = 0; i < len; i++) {
|
||||||
while (uart->UART_LSR & UART_LSR_RX_FIFO_EMPTY) {
|
while (!(uart->UART_LSR & UART_LSR_RDR)) {
|
||||||
/* Wait until the RX FIFO isn't empty */
|
/* Wait until it's possible to receive data. */
|
||||||
}
|
}
|
||||||
*((uint8_t *)buf + i) = uart->UART_THR_DLAB;
|
*((uint8_t *)buf + i) = uart->UART_THR_DLAB;
|
||||||
}
|
}
|
||||||
|
|
|
@ -157,6 +157,7 @@ typedef struct {
|
||||||
uint32_t UART_ASR;
|
uint32_t UART_ASR;
|
||||||
} tegra_uart_t;
|
} tegra_uart_t;
|
||||||
|
|
||||||
|
void uart_config(UartDevice dev);
|
||||||
void uart_init(UartDevice dev, uint32_t baud);
|
void uart_init(UartDevice dev, uint32_t baud);
|
||||||
void uart_wait_idle(UartDevice dev, UartVendorStatus status);
|
void uart_wait_idle(UartDevice dev, UartVendorStatus status);
|
||||||
void uart_send(UartDevice dev, const void *buf, size_t len);
|
void uart_send(UartDevice dev, const void *buf, size_t len);
|
||||||
|
|
Loading…
Reference in a new issue