Files
RTLPlayground/rtl837x_pins.c
René van Dorst f65d14f452 I2CBUS: Calculate I2C-settings as compiletime instead at runtime.
We can reduce the i2c-settings to just one byte, and this new const value
can directly be used by the I2C-peripheral without additional computation.
This saves 1-xdata load and a lot of bit-shifting.

I see a codesize savings of +200 bytes.
2026-09-20 11:25:34 +02:00

149 lines
3.4 KiB
C

#include "rtl837x_pins.h"
#include "rtl837x_common.h"
#include "rtl837x_sfr.h"
#include "rtl837x_regs.h"
#include "machine.h"
extern __code const struct machine machine;
extern __xdata uint8_t sfr_data[4];
#pragma codeseg BANK2
#pragma constseg BANK2
/* Returns RTL837X_REG_GPIO_XX_OUTPUT register address */
static uint16_t gpio_output_reg(uint8_t pin) __banked{
return pin < 32 ? RTL837X_REG_GPIO_00_31_OUTPUT : RTL837X_REG_GPIO_32_63_OUTPUT;
}
/* Returns RTL837X_REG_GPIO_XX_DIRECTION register address */
static uint16_t gpio_direction_reg(uint8_t pin) __banked {
return pin < 32 ? RTL837X_REG_GPIO_00_31_DIRECTION : RTL837X_REG_GPIO_32_63_DIRECTION;
}
/* Enable GPIO functions for pin */
static void gpio_mux_setup(uint8_t pin) __banked
{
// Some GPIOs require setting MUX registers to enable GPIO
switch (pin) {
case GPIO10_LED10:
reg_bit_clear(RTL837X_PIN_MUX_0, 10);
break;
case GPIO30_ACL_BIT3_EN:
reg_bit_clear(RTL837X_PIN_MUX_2, 3);
break;
case GPIO36_PWM_OUT:
reg_bit_set(RTL837X_PIN_MUX_1, 30);
break;
case GPIO37:
case GPIO38:
// Intentionally empty, always GPIO
break;
case GPIO46_I2C_SCL0:
// Bit 7-8 0b00 -> GPIO
reg_read_m(RTL837X_PIN_MUX_1);
sfr_mask_data(0, 0x80, 0x00);
sfr_mask_data(1, 0x01, 0x00);
reg_write_m(RTL837X_PIN_MUX_1);
break;
case GPIO50_I2C_SCL2_UART1_TX:
// Bit 15-16 0b00 -> GPIO
reg_read_m(RTL837X_PIN_MUX_1);
sfr_mask_data(1, 0x80, 0x00);
sfr_mask_data(2, 0x01, 0x00);
reg_write_m(RTL837X_PIN_MUX_1);
break;
case GPIO51_I2C_SDA2_UART1_RX:
// Bit 17-18 0b00 -> GPIO
reg_read_m(RTL837X_PIN_MUX_1);
sfr_mask_data(2, 0x06, 0x00);
reg_write_m(RTL837X_PIN_MUX_1);
break;
case GPIO54_ACL_BIT2_EN:
reg_bit_clear(RTL837X_PIN_MUX_2, 2);
break;
case GPIO_NA:
print_string("Attemped to assign GPIO function to N/A pin!");
break;
default:
print_string("GPIO MUX setup not implemented for pin="); print_byte(pin); print_string("\n");
}
}
void gpio_input_setup(uint8_t pin) __banked {
if (pin == GPIO_NA) {
return;
}
gpio_mux_setup(pin);
reg_bit_clear(gpio_direction_reg(pin), (pin % 32));
}
void gpio_output_setup(uint8_t pin, __xdata uint8_t initial_val) __banked{
if (pin == GPIO_NA) {
return;
}
gpio_mux_setup(pin);
// We need to setup value before enabling output on PIN
if (initial_val) {
reg_bit_set(gpio_output_reg(pin), (pin % 32));
} else {
reg_bit_clear(gpio_output_reg(pin), (pin % 32));
}
reg_bit_set(gpio_direction_reg(pin), (pin % 32));
}
/*
* Read up to 16 consecutive registers of the EEPROM via I2C into sfp_buf
*/
bool sfp_read_block(uint8_t slot, uint8_t reg, uint8_t len) __banked __reentrant
{
uint8_t dev;
uint8_t val;
len--;
if (len > 15)
return false;
dev = (reg & 0x80) ? 0x51 : 0x50; // 0x51 holds the diagnostics, 0x50 the module data
reg &= 0x7f;
REG_WRITE(RTL837X_REG_I2C_IN, 0, 0, 0, reg);
REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00,
0x1 << (I2C_MEM_ADDR_WIDTH - 16) | len,
(dev >> 5) | machine.sfp_port[slot].i2c,
((dev << 3) & 0xff) | 0x1);
do {
reg_read(RTL837X_REG_I2C_CTRL);
} while (SFR_DATA_0 & 0x1);
if (SFR_DATA_0 & 0x2)
return false;
for (uint8_t i = 0; i <= len; i++) {
switch (i & 0x3) {
case 0:
reg_read(RTL837X_REG_I2C_OUT + i);
val = SFR_DATA_0;
break;
case 1:
val = SFR_DATA_8;
break;
case 2:
val = SFR_DATA_16;
break;
default:
val = SFR_DATA_24;
break;
}
sfp_buf[i] = val;
}
return true;
}