mirror of
https://github.com/AsahiLinux/m1n1
synced 2024-11-10 09:44:13 +00:00
tunables: add initial version.
There are at least two types in the ADT related to USB, but there's a decent chance that there are even more required for other devices: * A simple tunable that applies to a whole device node and all its MMIO ranges specified in the "reg" property. This one seems to just be mask32. * A slightly more complex tunable that applies to a single MMIO range specified in the "reg" property. So far I've only seen 32 bit masks but the format looks like it should also support 8,16 and 64 bit masks. Signed-off-by: Sven Peter <sven@svenpeter.dev>
This commit is contained in:
parent
1134a4a649
commit
d73276b0bc
3 changed files with 144 additions and 1 deletions
2
Makefile
2
Makefile
|
@ -37,7 +37,7 @@ LIBFDT_OBJECTS := $(patsubst %,libfdt/%, \
|
|||
|
||||
OBJECTS := adt.o bootlogo_128.o bootlogo_256.o chickens.o exception.o exception_asm.o fb.o \
|
||||
heapblock.o kboot.o main.o memory.o memory_asm.o payload.o proxy.o smp.o start.o startup.o \
|
||||
string.o uart.o uartproxy.o utils.o utils_asm.o vsprintf.o wdt.o $(MINILZLIB_OBJECTS) \
|
||||
string.o tunables.o uart.o uartproxy.o utils.o utils_asm.o vsprintf.o wdt.o $(MINILZLIB_OBJECTS) \
|
||||
$(TINF_OBJECTS) $(DLMALLOC_OBJECTS) $(LIBFDT_OBJECTS)
|
||||
|
||||
DTS := t8103-j274.dts
|
||||
|
|
114
src/tunables.c
Normal file
114
src/tunables.c
Normal file
|
@ -0,0 +1,114 @@
|
|||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#include "adt.h"
|
||||
#include "tunables.h"
|
||||
#include "types.h"
|
||||
#include "utils.h"
|
||||
|
||||
struct tunable_info {
|
||||
int node_offset;
|
||||
int node_path[8];
|
||||
const u32 *tunable_raw;
|
||||
u32 tunable_len;
|
||||
};
|
||||
|
||||
static int tunables_adt_find(const char *path, const char *prop, struct tunable_info *info,
|
||||
u32 item_size)
|
||||
{
|
||||
info->node_offset = adt_path_offset_trace(adt, path, info->node_path);
|
||||
if (info->node_offset < 0) {
|
||||
printf("tunable: unable to find ADT node %s.\n", path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
info->tunable_raw = adt_getprop(adt, info->node_offset, prop, &info->tunable_len);
|
||||
if (info->tunable_raw == NULL || info->tunable_len == 0) {
|
||||
printf("tunable: Error getting ADT node %s property %s .\n", path, prop);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (info->tunable_len % item_size) {
|
||||
printf("tunable: tunable length needs to be a multiply of %d but is %d\n", item_size,
|
||||
info->tunable_len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
info->tunable_len /= item_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct tunable_global {
|
||||
u32 reg_idx;
|
||||
u32 offset;
|
||||
u32 mask;
|
||||
u32 value;
|
||||
} PACKED;
|
||||
|
||||
int tunables_apply_global(const char *path, const char *prop)
|
||||
{
|
||||
struct tunable_info info;
|
||||
|
||||
if (tunables_adt_find(path, prop, &info, sizeof(struct tunable_global)) < 0)
|
||||
return -1;
|
||||
|
||||
const struct tunable_global *tunables = (const struct tunable_global *)info.tunable_raw;
|
||||
for (u32 i = 0; i < info.tunable_len; ++i) {
|
||||
const struct tunable_global *tunable = &tunables[i];
|
||||
|
||||
u64 addr;
|
||||
if (adt_get_reg(adt, info.node_path, "reg", tunable->reg_idx, &addr, NULL) < 0) {
|
||||
printf("tunable: Error getting regs with index %d\n", tunable->reg_idx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
mask32(addr + tunable->offset, tunable->mask, tunable->value);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct tunable_local {
|
||||
u32 offset;
|
||||
u32 size;
|
||||
u64 mask;
|
||||
u64 value;
|
||||
} PACKED;
|
||||
|
||||
int tunables_apply_local(const char *path, const char *prop, u32 reg_offset)
|
||||
{
|
||||
struct tunable_info info;
|
||||
|
||||
if (tunables_adt_find(path, prop, &info, sizeof(struct tunable_local)) < 0)
|
||||
return -1;
|
||||
|
||||
u64 base;
|
||||
if (adt_get_reg(adt, info.node_path, "reg", reg_offset, &base, NULL) < 0) {
|
||||
printf("tunable: Error getting regs\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
const struct tunable_local *tunables = (const struct tunable_local *)info.tunable_raw;
|
||||
for (u32 i = 0; i < info.tunable_len; ++i) {
|
||||
const struct tunable_local *tunable = &tunables[i];
|
||||
|
||||
switch (tunable->size) {
|
||||
case 1:
|
||||
mask8(base + tunable->offset, tunable->mask, tunable->value);
|
||||
break;
|
||||
case 2:
|
||||
mask16(base + tunable->offset, tunable->mask, tunable->value);
|
||||
break;
|
||||
case 4:
|
||||
mask32(base + tunable->offset, tunable->mask, tunable->value);
|
||||
break;
|
||||
case 8:
|
||||
mask64(base + tunable->offset, tunable->mask, tunable->value);
|
||||
break;
|
||||
default:
|
||||
printf("tunable: unknown tunable size 0x%08x\n", tunable->size);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
29
src/tunables.h
Normal file
29
src/tunables.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef TUNABLES_H
|
||||
#define TUNABLES_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
/*
|
||||
* This function applies the tunables usually passed in the node "tunable".
|
||||
* They usually apply to multiple entries from the "reg" node.
|
||||
*
|
||||
* Example usage for the USB DRD node:
|
||||
* tunables_apply_global("/arm-io/usb-drd0", "tunable");
|
||||
*/
|
||||
int tunables_apply_global(const char *path, const char *prop);
|
||||
|
||||
/*
|
||||
* This function applies the tunables specified in device-specific tunable properties.
|
||||
* These only apply to a single MMIO region from the "reg" node which needs to
|
||||
* be specified.
|
||||
*
|
||||
* Example usage for two tunables from the USB DRD DART node:
|
||||
* tunables_apply_local("/arm-io/dart-usb0", "dart-tunables-instance-0", 0);
|
||||
* tunables_apply_local("/arm-io/dart-usb0", "dart-tunables-instance-1", 1);
|
||||
*
|
||||
*/
|
||||
int tunables_apply_local(const char *path, const char *prop, u32 reg_idx);
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue