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
11 changes: 8 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ endif()
# Same shape as IPCHW_VENDORS above, and for the same reason -- set(... CACHE)
# here means a parent project has to FORCE it.
set(IPCHW_PADMUX_FAMILIES v1 v2 v2a v3 v3a v4 v4a v5 3536c 3536d sstar
ingenic novatek xm)
ingenic novatek xm fh)
set(IPCHW_PADMUX "all" CACHE STRING
"Pad-mux tables compiled into libipchw: 'all', 'none', or a subset of ${IPCHW_PADMUX_FAMILIES}")

Expand Down Expand Up @@ -107,6 +107,11 @@ if("xm" IN_LIST _padmux_selected AND NOT "xm" IN_LIST _ipchw_selected)
list(REMOVE_ITEM _padmux_selected xm)
list(REMOVE_ITEM IPCHW_PADMUX_DEFS IPCHW_PADMUX_XM)
endif()
# Fullhan's likewise: only hal/fh.c sets the chip_generation that reaches it.
if("fh" IN_LIST _padmux_selected AND NOT "fh" IN_LIST _ipchw_selected)
list(REMOVE_ITEM _padmux_selected fh)
list(REMOVE_ITEM IPCHW_PADMUX_DEFS IPCHW_PADMUX_FH)
endif()
message(STATUS "libipchw pad-mux tables: ${_padmux_selected}")

# The vendors whose pad-mux is its own backend rather than a table in
Expand All @@ -116,13 +121,13 @@ message(STATUS "libipchw pad-mux tables: ${_padmux_selected}")
# SigmaStar tables in a build that detects nothing else, which is exactly what
# reginfo_test does.
set(IPCHW_PADMUX_BACKENDS "")
foreach(_f sstar ingenic novatek xm)
foreach(_f sstar ingenic novatek xm fh)
if(_f IN_LIST _padmux_selected)
list(APPEND IPCHW_PADMUX_BACKENDS src/hal/${_f}_padmux.c)
endif()
endforeach()
set(IPCHW_PADMUX_BACKENDS_ALL src/hal/sstar_padmux.c src/hal/ingenic_padmux.c
src/hal/novatek_padmux.c src/hal/xm_padmux.c)
src/hal/novatek_padmux.c src/hal/xm_padmux.c src/hal/fh_padmux.c)

# Which HiSilicon generations libipchw can identify. IPCHW_VENDORS does not
# reach the CODE: chipid.c dispatches to the HiSilicon HAL directly rather
Expand Down
51 changes: 50 additions & 1 deletion docs/padmux.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ puts the pad back.
> pad to GPIO. A pad that a MISC-style table drop hides from `reginfo --pads`
> still answers here, which is the one place to see it.

## Five vendors, four mechanisms
## Six vendors, four mechanisms

This is the thing to understand before touching any of it. The API looks like
one question, and underneath it is four different pieces of silicon.
Expand Down Expand Up @@ -382,6 +382,44 @@ is clock, command or data, so those pads carry the bus's name, as SigmaStar's
modes do. `chip_generation` is `CHIP_XM510` or `CHIP_XM530` (XM550 is the
XM530 die), set by `xm_detect_cpu()`.

### Fullhan -- a selector per pad, addressed by GPIO number

FH8852, FH8856 and FH8858, V100, V200 and V210, are HiSilicon's shape exactly:
one register per pad in the PMU block at `0xF0000080 + 4 * pad`, and a four-bit
selector (`mfs`) in bits 24..27 of it. The functions each pad offers are the
vendor kernel's own `iopad.h` -- `PINCTRL_FUNC(SSI0_D2, 46, FUNC0, ...)` --
generated into `src/hal/fh_padmux.h`.

Two things are not HiSilicon's:

- **The register is indexed by the vendor's pad id, but a pad is addressed by
its GPIO number**, which is what the kernel exports (`/sys/class/gpio/GPIO9`
is pad 46 on V200, pad 44 on V100). Every call takes and returns the GPIO
number. The few pads with no GPIO function have no number to pass, so they
appear in a walk of the whole table and nowhere else. A plain number is a
GPIO number, never a pad id, and the `5_2` spelling is refused.
- **A mux write sets four fields, not one.** The kernel's own mux
(`fh_pinctrl_func_select()`) writes the selector together with the pad's
input, output and Schmitt enables, and clears both enables on a pad no
device claims at boot. A write here does the same as the kernel's.
`func_mask` covers all four, so a composed read-modify-write does what the
kernel does; `get()` reads the selector alone. Pull and drive strength are
left as they are.

The six V200/V210 parts share one table and the two V100 parts another; the
generator proves that by parsing each file rather than assuming it from the
names. FH8856V201 and FH8858V201 are recognised but answer "no table": the
vendor kernel ships none for them. `chip_generation` is one of the
`CHIP_FH*` values in `hal/fh.h`, set by `fh_detect_cpu()`.

Several pads double as boot-flash lines -- on V200, GPIO7..GPIO10 are also
`SSI0_TXD`, `SSI0_RXD`, `SSI0_D2` and `SSI0_D3` -- and neither the table nor
the hardware says whether a board's flash is using them: the pad enables do not
tell (input enable reads set on every pad, output enable reads clear on every
pad). So `ipchw_padmux_set()` refuses, with `IPCHW_PADMUX_IN_USE` and nothing
written, to move a pad off any `SSI0_*` function. `ipchw_padmux_set_forced()`
and `gpio mux <pad> <function> --force` are for whoever knows the board.

## Pad numbers and names

`gpio_pad` is the number the kernel uses, and it is the number to speak to
Expand All @@ -395,6 +433,7 @@ every consumer:
| Novatek | the Linux GPIO number, `group * 32 + pin` | `"P_GPIO22"` |
| Xiongmai XM530/XM550 | the pad, as the vendor's `GPIO N` | `"GPIO43"` |
| Xiongmai XM510 | `port * 8 + pin` | `"GPIO8_1"` |
| Fullhan | the GPIO number the kernel exports, not the pad id | `"GPIO9"` |

Function names are the vendor's own and are **not portable**, not even within
HiSilicon: `PWM_OUT0` on V1, `PWM0` from V2, `PWM0_OUT1` on V5. `"PWM"` also
Expand Down Expand Up @@ -432,6 +471,16 @@ tools/gen_ingenic_padmux.py \
Each generated header carries the exact command that made it, so the recipe
above is only the shape; the header is the record.

Fullhan, from the vendor kernel's per-chip `iopad.h`, one `--table` per
distinct layout; files under one tag must parse to the same rows:

```sh
tools/gen_fh_padmux.py \
--table V200=<fullhan-fh8852v200>/arch/arm/mach-fh/fh8852v200/iopad.h,... \
--table V100=<fullhan-fh8852v100>/arch/arm/mach-fh/include/mach/fh8852_iopad.h,... \
> src/hal/fh_padmux.h
```

Novatek is generated differently, because its source is code and not a table:

```sh
Expand Down
10 changes: 10 additions & 0 deletions include/ipchw.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ enum {
IPCHW_PADMUX_NO_PAD = -4, /* this SoC has no pad with that number */
IPCHW_PADMUX_NO_FUNC = -5, /* that pad cannot carry that function */
IPCHW_PADMUX_IO = -6, /* a register could not be reached */
IPCHW_PADMUX_IN_USE = -7, /* the pad is carrying something the board
* runs from -- see ipchw_padmux_set() */
};

enum {
Expand Down Expand Up @@ -164,4 +166,12 @@ int ipchw_padmux_get(int pad, ipchw_padmux_t *out);
* WRITES /dev/mem; see the threading note above. */
int ipchw_padmux_set(int pad, const char *func_name);

/* ipchw_padmux_set() also refuses, with IPCHW_PADMUX_IN_USE and nothing
* written, to move a pad off a function the board is running from where the
* backend can tell: on Fullhan, a boot-flash line the kernel set up at boot.
* The same pad carrying that function unused is not refused. This is the one
* call that skips the check, for an operator who knows better -- and for a
* test that cycles every pad through every function. */
int ipchw_padmux_set_forced(int pad, const char *func_name);

#endif /* IPCHW_H */
11 changes: 11 additions & 0 deletions src/hal/fh.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include <unistd.h>

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

Expand Down Expand Up @@ -37,37 +38,47 @@ bool fh_detect_cpu(char *chip_name) {
switch (sysctrl & 0xffffff) {
case 0x00000001:
strcpy(chip_name, "FH8852V200");
chip_generation = CHIP_FH8852V200;
break;
case 0x00100001:
strcpy(chip_name, "FH8856V200");
chip_generation = CHIP_FH8856V200;
break;
case 0x00410001:
strcpy(chip_name, "FH8858V200");
chip_generation = CHIP_FH8858V200;
break;
case 0x00000002:
strcpy(chip_name, "FH8852V210");
chip_generation = CHIP_FH8852V210;
break;
case 0x00100002:
strcpy(chip_name, "FH8856V210");
chip_generation = CHIP_FH8856V210;
break;
case 0x00410002:
strcpy(chip_name, "FH8858V210");
chip_generation = CHIP_FH8858V210;
break;
case 0x00200001:
strcpy(chip_name, "FH8856V201");
chip_generation = CHIP_FH8856V201;
break;
case 0x00300001:
strcpy(chip_name, "FH8858V201");
chip_generation = CHIP_FH8858V201;
break;
}
break;
case 0x17092901:
switch (ipver & 0xf) {
case 0xc:
strcpy(chip_name, "FH8852V100");
chip_generation = CHIP_FH8852V100;
break;
case 0xd:
strcpy(chip_name, "FH8856V100");
chip_generation = CHIP_FH8856V100;
break;
}
break;
Expand Down
16 changes: 16 additions & 0 deletions src/hal/fh.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,22 @@
#define REG_PMU_FW_VER (PMU_REG_BASE + 0x0008)
#define REG_PMU_SYS_CTRL (PMU_REG_BASE + 0x000c)

/* chip_generation for the parts hal/fh_padmux.c has a pad table for, and the
* two it knows it has none for. "FH", the model, and a last nibble for the
* revision: 1 V100, 2 V200, 3 V210, 4 V201. */
enum {
CHIP_FH8852V100 = 0x46488521,
CHIP_FH8856V100 = 0x46488561,
CHIP_FH8852V200 = 0x46488522,
CHIP_FH8856V200 = 0x46488562,
CHIP_FH8858V200 = 0x46488582,
CHIP_FH8852V210 = 0x46488523,
CHIP_FH8856V210 = 0x46488563,
CHIP_FH8858V210 = 0x46488583,
CHIP_FH8856V201 = 0x46488564,
CHIP_FH8858V201 = 0x46488584,
};

bool fh_detect_cpu(char *chip_name);
unsigned long fh_totalmem(unsigned long *media_mem);
void fh_setup_hal();
Expand Down
Loading
Loading