Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,8 @@ set(_common_lib_src_tail

# Full set, used by the ipctool executable
set(COMMON_LIB_SRC_ALL ${_common_lib_src_head} ${IPCHW_HISI_SRC_ALL}
${_common_lib_src_tail} ${IPCHW_PADMUX_BACKENDS_ALL})
${_common_lib_src_tail} ${IPCHW_PADMUX_BACKENDS_ALL}
src/hal/sstar_gpio.c src/hal/sstar_gpio.h)
foreach(_v IN LISTS IPCHW_OPTIONAL_VENDORS)
list(APPEND COMMON_LIB_SRC_ALL src/hal/${_v}.c src/hal/${_v}.h)
string(TOUPPER ${_v} _V)
Expand All @@ -295,6 +296,9 @@ foreach(_v IN LISTS _ipchw_selected)
"expected 'all', 'none', or a subset of ${IPCHW_OPTIONAL_VENDORS}")
endif()
list(APPEND COMMON_LIB_SRC src/hal/${_v}.c src/hal/${_v}.h)
if(_v STREQUAL "sstar")
list(APPEND COMMON_LIB_SRC src/hal/sstar_gpio.c src/hal/sstar_gpio.h)
endif()
string(TOUPPER ${_v} _V)
list(APPEND IPCHW_VENDOR_DEFS IPCHW_VENDOR_${_V})
endforeach()
Expand Down
13 changes: 13 additions & 0 deletions docs/gpio.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@ ipctool gpio set <pad> <value> # WRITES: drive the pad
`<pad>` is accepted in either spelling, `5_6` (group 5, bit 6) or `46`
(linear, = group * 8 + bit). Both appear in `gpio scan` output.

On SigmaStar the two spellings are one: pads are already numbered linearly and
there is no `group_bit` form. The pad number is the number the kernel's
gpiochip uses, so `gpio get 23` and `/sys/class/gpio/gpio23` describe the same
wire. The `gpio scan` baseline differs in shape as well — one `Pad:` line per
GPIO pad, decoded from the pad's own one-byte register into what it reads
(`in`), what the SoC is driving (`out`) and whether it drives at all (`oe_n`,
1 meaning input/Hi-Z) — rather than the per-group data and direction words.

## `gpio scan`

It prints a baseline table of every GPIO pad, then polls in a loop and reports
Expand Down Expand Up @@ -110,6 +118,11 @@ to reporting every output currently sitting low, which is a much broader guess.
So a short list means the first rule fired and is worth trusting; a long one
means the second did.

On SigmaStar the two rules survive with pads in place of groups: when the
streamer maps the GPIO block, a board whose whole pad list holds only one or
two driving pads gets exactly those, and without a streamer every pad
currently driving low is reported.

IR-cut is nearly always a *pair* of pads, driven in opposite directions to flip
the filter between its two positions. To confirm a pair, run `gpio scan` and
switch the camera between day and night mode in the web UI. Both pads change in
Expand Down
95 changes: 95 additions & 0 deletions src/hal/sstar_gpio.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/* SigmaStar per-pad GPIO registers.
*
* Where HiSilicon banks eight pins behind one data and one direction word,
* SigmaStar's Infinity6C gives every pad its own one-byte register: bit 0 is
* the pin level, bit 1 the output value, and bit 2 the output enable, which
* on this family reads 1 while the pad drives Hi-Z (an input) and 0 while it
* drives. Like the pad-mux ports these registers are 16-bit slots in
* four-byte RIU holes, so they are reached with the 16-bit accessors and a
* 32-bit store would write two bytes that do not exist.
*
* The table below is the one the vendor's own driver carries
* (drivers/sstar/gpio/infinity6c/mhal_gpio.c in the SigmaStar kernel, GPL-2)
* converted from RIU byte offset r to physical 0x1F207C00 + 2 * r, and the
* result was measured against a live Infinity6C board: writing pads 12 and 30
* through sysfs moves their bytes at exactly these addresses, and the idle
* levels of pads 10, 23 and 40/41 read back the states their exporters had
* left. The four PAD_ETH_* pads the vendor adds by hand sit outside the
* gpiochip range and are not listed. */

#include "hal/sstar_gpio.h"

#include <string.h>

#include "chipid.h"
#include "hal/sstar.h"
#include "tools.h"

static const uint32_t i6c_gpio_regs[] = {
0x1F207C00, 0x1F207C04, 0x1F207C08, 0x1F207C0C, 0x1F207C10, 0x1F207C14,
0x1F207C18, 0x1F207C1C, 0x1F207C20, 0x1F207C24, 0x1F207C28, 0x1F207C2C,
0x1F207C30, 0x1F207C34, 0x1F207C38, 0x1F207C3C, 0x1F207C40, 0x1F207C44,
0x1F207C48, 0x1F207C4C, 0x1F207C50, 0x1F207C54, 0x1F207C58, 0x1F207C5C,
0x1F207C64, 0x1F207C68, 0x1F207C6C, 0x1F207C70, 0x1F207C74, 0x1F207C78,
0x1F207C7C, 0x1F207C80, 0x1F207C84, 0x1F207C88, 0x1F207C8C, 0x1F207C90,
0x1F207C94, 0x1F207C98, 0x1F207C9C, 0x1F207CA0, 0x1F207CA4, 0x1F207CA8,
0x1F207CC4, 0x1F207CC8, 0x1F207CCC, 0x1F207CD0, 0x1F207CD4, 0x1F207CD8,
0x1F207CDC, 0x1F207CE0, 0x1F207CE4, 0x1F207CE8, 0x1F207CEC, 0x1F207CF0,
0x1F207CF4, 0x1F207CF8, 0x1F207CFC, 0x1F207D00, 0x1F207D04, 0x1F207D08,
0x1F207D0C, 0x1F207D10, 0x1F207D14, 0x1F207D18, 0x1F207D1C, 0x1F207D20,
0x1F207D24, 0x1F207D28, 0x1F207D2C, 0x1F207D30, 0x1F207D34, 0x1F207D38,
0x1F207D3C, 0x1F207D40, 0x1F207D44, 0x1F207D48, 0x1F207D4C, 0x1F207D50,
0x1F207D54, 0x1F207D58, 0x1F207D5C, 0x1F207D60,
};

bool sstar_gpio_supported(void) {
switch (chip_generation) {
case INFINITY6C:
return true;
default:
return false;
}
}

int sstar_gpio_num_pads(void) {
if (!sstar_gpio_supported())
return 0;
return (int)(sizeof(i6c_gpio_regs) / sizeof(i6c_gpio_regs[0]));
}

uint32_t sstar_gpio_pad_addr(int pad) {
if (pad < 0 || pad >= sstar_gpio_num_pads())
return 0;
return i6c_gpio_regs[pad];
}

bool sstar_gpio_window(uint32_t *base, uint32_t *len) {
int nr_pads = sstar_gpio_num_pads();
if (!nr_pads)
return false;
*base = sstar_gpio_pad_addr(0) & ~0xfffu;
*len = sstar_gpio_pad_addr(nr_pads - 1) + 4 - *base;
return true;
}

bool sstar_gpio_read(int pad, uint8_t *val) {
uint32_t addr = sstar_gpio_pad_addr(pad);
if (!addr)
return false;
uint32_t data;
if (!mem_reg(addr, &data, OP_READ_16))
return false;
*val = (uint8_t)(data & 0xff);
return true;
}

bool sstar_gpio_write(int pad, uint8_t val) {
uint32_t addr = sstar_gpio_pad_addr(pad);
if (!addr)
return false;
uint32_t data;
if (!mem_reg(addr, &data, OP_READ_16))
return false;
data = (data & 0xff00) | val;
return mem_reg(addr, &data, OP_WRITE_16);
}
31 changes: 31 additions & 0 deletions src/hal/sstar_gpio.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#ifndef HAL_SSTAR_GPIO_H
#define HAL_SSTAR_GPIO_H

#include <stdbool.h>
#include <stdint.h>

/* Bit layout of the per-pad register, as the vendor driver uses it. */
#define SSTAR_GPIO_BIT_IN 0x01
#define SSTAR_GPIO_BIT_OUT 0x02
#define SSTAR_GPIO_BIT_INPUT 0x04

bool sstar_gpio_supported(void);
int sstar_gpio_num_pads(void);

/* Physical address of the pad's register, or 0 when there is no table for the
* current chip family or the pad is out of range. */
uint32_t sstar_gpio_pad_addr(int pad);

/* The one window every pad register of the chip sits in, from the page the
* first pad lives on to the end of the last pad's slot: what a daemon has to
* have mapped to be holding the pads. False when there is no table. */
bool sstar_gpio_window(uint32_t *base, uint32_t *len);

/* One pad's register through /dev/mem. Reads take the low byte of the 16-bit
* slot; writes read-modify-write it and leave the upper byte alone, because a
* wider store reaches RIU bytes that are not mapped. Serialise the callers:
* mem_reg() is single-threaded by contract. */
bool sstar_gpio_read(int pad, uint8_t *val);
bool sstar_gpio_write(int pad, uint8_t val);

#endif /* HAL_SSTAR_GPIO_H */
Loading
Loading