kernel-brax3-ubuntu-touch/drivers/misc/mediatek/memblock/mtk-memblock.c
erascape f319b992b1 kernel-5.15: Initial import brax3 UT kernel
* halium configs enabled

Signed-off-by: erascape <erascape@proton.me>
2025-09-23 15:17:10 +00:00

278 lines
4.9 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2020 MediaTek Inc.
*/
#include <linux/init.h>
#include <linux/memblock.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/of_fdt.h>
#include <linux/percpu.h>
#include <linux/string.h>
#include <asm/memory.h>
#include <asm/pgtable.h>
#include <asm/sections.h>
#include <asm/smp_plat.h>
#include <asm/stacktrace.h>
#include <asm/system_misc.h>
struct module_sect_attr {
struct bin_attribute battr;
unsigned long address;
};
struct module_sect_attrs {
struct attribute_group grp;
unsigned int nsections;
struct module_sect_attr attrs[0];
};
#define KV kimage_vaddr
#define S_MAX SZ_32M
#define SM_SIZE 28
#define TT_SIZE 256
#define NAME_LEN 128
static unsigned long *mb_ka;
static int *mb_ko;
static unsigned long *mb_krb;
static unsigned int *mb_kns;
static u8 *mb_kn;
static unsigned int *mb_km;
static u8 *mb_ktt;
static u16 *mb_kti;
static void *mb_abt_addr(void)
{
void *ssa = (void *)(KV);
void *pos;
u8 abt[SM_SIZE];
int i;
u32 s_left;
for (i = 0; i < SM_SIZE; i++) {
if (i & 0x1)
abt[i] = 0;
else
abt[i] = 0x61 + i / 2;
}
pos = ssa;
s_left = S_MAX;
while ((u64)pos < (u64)(ssa + S_MAX)) {
pos = memchr(pos, 'a', s_left);
if (!pos) {
pr_info("fail at: 0x%lx @ 0x%x\n", ssa, s_left);
return NULL;
}
s_left = ssa + S_MAX - pos;
if (!memcmp(pos, (const void *)abt, sizeof(abt)))
return pos;
pos += 1;
}
pr_info("fail at end: 0x%lx @ 0x%x\n", ssa, s_left);
return NULL;
}
static unsigned long *mb_krb_addr(void)
{
void *abt_addr = mb_abt_addr();
unsigned long *ssa;
int i;
if (!abt_addr)
return NULL;
ssa = (unsigned long *)round_up((unsigned long)abt_addr, 8);
for (i = 0; i < SZ_1M ; i++) {
if (*ssa == KV)
return ssa;
ssa--;
}
pr_info("krb not found: 0x%lx\n", ssa);
return NULL;
}
static unsigned int *mb_km_addr(void)
{
const u8 *name = mb_kn;
unsigned int loop = *mb_kns;
while (loop--)
name = name + (*name) + 1;
return (unsigned int *)round_up((unsigned long)name, 8);
}
static u16 *mb_kti_addr(void)
{
const u8 *pch = mb_ktt;
int loop = TT_SIZE;
while (loop--) {
for (; *pch; pch++)
;
pch++;
}
return (u16 *)round_up((unsigned long)pch, 8);
}
int mb_ka_init(void)
{
unsigned int kns;
mb_krb = mb_krb_addr();
if (!mb_krb)
return -EINVAL;
mb_kns = (unsigned int *)(mb_krb + 1);
mb_kn = (u8 *)(mb_krb + 2);
kns = *mb_kns;
mb_ko = (int *)(mb_krb - (round_up(kns, 2) / 2));
mb_km = mb_km_addr();
mb_ktt = (u8 *)round_up((unsigned long)(mb_km +
(round_up(kns, 256) / 256)), 8);
mb_kti = mb_kti_addr();
return 0;
}
static unsigned int mb_checking_names(unsigned int off,
char *namebuf, size_t buflen)
{
int len, skipped_first = 0;
const u8 *tptr, *data;
data = mb_kn + off;
len = *data;
data++;
off += len + 1;
while (len) {
tptr = mb_ktt + *(mb_kti + *data);
data++;
len--;
while (*tptr) {
if (skipped_first) {
if (buflen <= 1)
goto tail;
*namebuf = *tptr;
namebuf++;
buflen--;
} else
skipped_first = 1;
tptr++;
}
}
tail:
if (buflen)
*namebuf = '\0';
return off;
}
static unsigned long mb_idx2addr(int idx)
{
if (!IS_ENABLED(CONFIG_KALLSYMS_BASE_RELATIVE))
return *(mb_ka + idx);
if (!IS_ENABLED(CONFIG_KALLSYMS_ABSOLUTE_PERCPU))
return *mb_krb + (u32)(*(mb_ko + idx));
if (*(mb_ko + idx) >= 0)
return *(mb_ko + idx);
return *mb_krb - 1 - *(mb_ko + idx);
}
static unsigned long mb_addr_find(const char *name)
{
char strbuf[NAME_LEN];
unsigned long i;
unsigned int off;
for (i = 0, off = 0; i < *mb_kns; i++) {
off = mb_checking_names(off, strbuf, ARRAY_SIZE(strbuf));
if (strcmp(strbuf, name) == 0)
return mb_idx2addr(i);
}
return 0;
}
static struct memblock *p_memblock;
static struct memblock *mb_get_memblock(void)
{
if (p_memblock)
return p_memblock;
p_memblock = (void *)(mb_addr_find("memblock"));
if (!p_memblock) {
pr_info("%s failed", __func__);
return NULL;
}
return p_memblock;
}
phys_addr_t mb_start_of_DRAM(void)
{
struct memblock *memblockp = mb_get_memblock();
if (!memblockp) {
pr_info("%s failed", __func__);
return 0;
}
return memblockp->memory.regions[0].base;
}
EXPORT_SYMBOL_GPL(mb_start_of_DRAM);
phys_addr_t mb_end_of_DRAM(void)
{
struct memblock *memblockp = mb_get_memblock();
int idx;
if (!memblockp) {
pr_info("%s failed", __func__);
return 0;
}
idx = memblockp->memory.cnt - 1;
return (memblockp->memory.regions[idx].base +
memblockp->memory.regions[idx].size);
}
EXPORT_SYMBOL_GPL(mb_end_of_DRAM);
static int __init mb_init(void)
{
int ret;
return 0;
ret = mb_ka_init();
if (ret) {
pr_info("mb_ka_init failed: %d", ret);
return ret;
}
mb_get_memblock();
return 0;
}
arch_initcall(mb_init);
MODULE_AUTHOR("Zhiyong Wang <zhiyong.wang@mediatek.com>");
MODULE_AUTHOR("Stanley Chu <stanley chu@mediatek.com>");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Memory Block");