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:
Sven Peter 2021-03-15 21:10:19 +01:00 committed by Hector Martin
parent 1134a4a649
commit d73276b0bc
3 changed files with 144 additions and 1 deletions

View file

@ -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
View 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
View 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