luckfox-pico-sdk/sysdrv/source/kernel/arch/arm/mach-rockchip/rkpm_helpers.c
luckfox-eng29 8f34c2760d project:build.sh: Added fastboot support; custom modifications to U-Boot and kernel implemented using patches.
project:cfg:BoardConfig_IPC: Added fastboot BoardConfig file and firmware post-scripts, distinguishing between
the BoardConfigs for Luckfox Pico Pro and Luckfox Pico Max. project:app: Added fastboot_client and rk_smart_door
for quick boot applications; updated rkipc app to adapt to the latest media library. media:samples: Added more
usage examples. media:rockit: Fixed bugs; removed support for retrieving data frames from VPSS. media:isp:
Updated rkaiq library and related tools to support connection to RKISP_Tuner. sysdrv:Makefile: Added support for
compiling drv_ko on Luckfox Pico Ultra W using Ubuntu; added support for custom root filesystem.
sysdrv:tools:board: Updated Buildroot optional mirror sources, updated some software versions, and stored device
tree files and configuration files that undergo multiple modifications for U-Boot and kernel separately.
sysdrv:source:mcu: Used RISC-V MCU SDK with RT-Thread system, mainly for initializing camera AE during quick
boot. sysdrv:source:uboot: Added support for fastboot; added high baud rate DDR bin for serial firmware upgrades.
sysdrv:source:kernel: Upgraded to version 5.10.160; increased NPU frequency for RV1106G3; added support for
fastboot.

Signed-off-by: luckfox-eng29 <eng29@luckfox.com>
2024-10-14 09:47:04 +08:00

239 lines
4.7 KiB
C

// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2023 Rockchip Electronics Co., Ltd.
*/
#include <asm/arch_timer.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include "rkpm_helpers.h"
/* REG region */
#define RGN_LEN(_rgn) (((_rgn)->end - (_rgn)->start) / (_rgn)->stride + 1)
static u32 *region_mem;
static u32 region_mem_size;
static int region_mem_idx;
static int alloc_region_mem(u32 *buf, int max_len,
struct reg_region *rgns, u32 rgn_num)
{
int i;
int total_len = 0, len = 0;
struct reg_region *r = rgns;
if (!buf || !rgns) {
pr_err("%s invalid parameter\n", __func__);
return 0;
}
for (i = 0; i < rgn_num; i++, r++) {
if (total_len < max_len)
r->buf = &buf[total_len];
len = RGN_LEN(r);
total_len += len;
}
if (len >= max_len) {
pr_err("%s The buffer remain length:%d is too small for region:0x%x, at least %d\n",
__func__, max_len, rgns[0].start, total_len);
return -ENOMEM;
}
return total_len;
}
/**
* Alloc memory to reg_region->buf from region_mem.
* @rgns - struct reg_region array.
* @rgn_num - struct reg_region array length.
*/
void rkpm_alloc_region_mem(struct reg_region *rgns, u32 rgn_num)
{
int max_len = 0, len;
max_len = region_mem_size / sizeof(u32) -
region_mem_idx;
len = alloc_region_mem(region_mem + region_mem_idx, max_len,
rgns, rgn_num);
region_mem_idx += len;
}
void rkpm_region_mem_init(u32 size)
{
if (!size) {
pr_err("%s invalid param\n", __func__);
return;
}
region_mem = kmalloc(size, GFP_KERNEL);
if (!region_mem) {
pr_err("%s malloc region memory (0x%x) err\n", __func__, size);
return;
}
region_mem_size = size;
}
/**
* Save (reg_region->start ~ reg_region->end) to reg_region->buf.
* @rgns - struct reg_region array.
* @rgn_num - struct reg_region array length.
*/
void rkpm_reg_rgn_save(struct reg_region *rgns, u32 rgn_num)
{
struct reg_region *r;
u8 *addr;
u8 *start, *end;
int i, j;
for (i = 0; i < rgn_num; i++) {
r = &rgns[i];
start = (char *)(*r->base) + r->start;
end = (char *)(*r->base) + r->end;
for (j = 0, addr = start; addr <= end; addr += r->stride, j++)
r->buf[j] = readl_relaxed(addr);
}
}
/**
* Restore reg_region->buf to (reg_region->start ~ reg_region->end).
* @rgns - struct reg_region array.
* @rgn_num - struct reg_region array length.
*/
void rkpm_reg_rgn_restore(struct reg_region *rgns, u32 rgn_num)
{
struct reg_region *r;
u8 *addr;
u8 *start, *end;
int i, j;
for (i = 0; i < rgn_num; i++) {
r = &rgns[i];
start = (char *)(*r->base) + r->start;
end = (char *)(*r->base) + r->end;
for (j = 0, addr = start; addr <= end; addr += r->stride, j++)
writel_relaxed(r->buf[j] | r->wmsk, addr);
}
}
void rkpm_reg_rgn_restore_reverse(struct reg_region *rgns, u32 rgn_num)
{
struct reg_region *r;
u8 *addr;
u8 *start, *end;
int i, j;
for (i = rgn_num - 1; i >= 0; i--) {
r = &rgns[i];
start = (char *)(*r->base) + r->start;
end = (char *)(*r->base) + r->end;
j = RGN_LEN(r) - 1;
for (addr = end; addr >= start; addr -= r->stride, j--)
writel_relaxed(r->buf[j] | r->wmsk, addr);
}
}
/**
* Dump reg regions
* @rgns - struct reg_region array.
* @rgn_num - struct reg_region array length.
*/
void rkpm_dump_reg_rgns(struct reg_region *rgns, u32 rgn_num)
{
struct reg_region *r;
int i;
for (i = 0; i < rgn_num; i++) {
r = &rgns[i];
rkpm_regs_dump(*r->base, r->start, r->end, r->stride);
}
}
#pragma weak rkpm_printch
void rkpm_printch(int c)
{
}
void rkpm_printstr(const char *s)
{
while (*s) {
rkpm_printch(*s);
s++;
}
}
void rkpm_printhex(u32 hex)
{
u8 i = 8;
u8 c;
rkpm_printch('0');
rkpm_printch('x');
while (i--) {
c = (hex & 0xf0000000) >> 28;
rkpm_printch(c < 0xa ? c + '0' : c - 0xa + 'a');
hex <<= 4;
}
}
void rkpm_printdec(int dec)
{
int i, tmp = dec;
if (dec < 0) {
rkpm_printch('-');
tmp = -dec;
dec = -dec;
}
for (i = 1; tmp / 10; tmp /= 10, i *= 10)
;
for (; i >= 1; i /= 10) {
rkpm_printch('0' + (char)(dec / i));
dec %= i;
}
}
void rkpm_regs_dump(void __iomem *base,
u32 start_offset,
u32 end_offset,
u32 stride)
{
u32 i;
for (i = start_offset; i <= end_offset; i += stride) {
if ((i - start_offset) % 16 == 0) {
rkpm_printch('\n');
rkpm_printhex((u32)base + i);
rkpm_printch(':');
rkpm_printch(' ');
rkpm_printch(' ');
rkpm_printch(' ');
rkpm_printch(' ');
}
rkpm_printhex(readl_relaxed(base + i));
rkpm_printch(' ');
rkpm_printch(' ');
rkpm_printch(' ');
rkpm_printch(' ');
}
rkpm_printch('\n');
}
void rkpm_raw_udelay(int us)
{
u64 cur_cnt = __arch_counter_get_cntpct();
u64 del = us * 24;
while (__arch_counter_get_cntpct() - cur_cnt < del)
;
}