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>
461 lines
12 KiB
C
461 lines
12 KiB
C
/**
|
|
******************************************************************************
|
|
*
|
|
* @file rwnx_platform.c
|
|
*
|
|
* Copyright (C) RivieraWaves 2012-2019
|
|
*
|
|
******************************************************************************
|
|
*/
|
|
#include <linux/module.h>
|
|
#include <linux/firmware.h>
|
|
#include <linux/delay.h>
|
|
|
|
#include "rwnx_platform.h"
|
|
#include "reg_access.h"
|
|
#include "hal_desc.h"
|
|
#include "rwnx_main.h"
|
|
#include "virt_net.h"
|
|
|
|
//#include "rwnx_pci.h"
|
|
#ifndef CONFIG_RWNX_FHOST
|
|
//#include "ipc_host.h"
|
|
#endif /* !CONFIG_RWNX_FHOST */
|
|
//#include "rwnx_msg_tx.h"
|
|
|
|
#ifdef AICWF_SDIO_SUPPORT
|
|
#include "aicwf_sdio.h"
|
|
#endif
|
|
|
|
#ifdef AICWF_USB_SUPPORT
|
|
#include "aicwf_usb.h"
|
|
#endif
|
|
|
|
// Parser state
|
|
#define INIT 0
|
|
#define CMD 1
|
|
#define PRINT 2
|
|
#define GET_VALUE 3
|
|
|
|
struct rwnx_plat *g_rwnx_plat = NULL;
|
|
struct rwnx_vif g_rwnx_vif = {{0}};
|
|
|
|
#ifdef CONFIG_VNET_MODE
|
|
extern aicwf_custom_msg_vnet g_custom_msg_vnet;
|
|
int rwnx_platform_set_mac_addr(void)
|
|
{
|
|
struct custom_msg_set_mac_req mac;
|
|
mac.hdr.cmd_id = CUST_CMD_SET_MAC_ADDR_REQ;
|
|
memcpy(mac.mac_addr, g_custom_msg_vnet.macaddr_cfm.mac_addr, 6);
|
|
printk("mac addr: %02X %02X\r\n",
|
|
g_custom_msg_vnet.macaddr_cfm.mac_addr[0], g_custom_msg_vnet.macaddr_cfm.mac_addr[5]);
|
|
rwnx_tx_msg((u8 *)&mac, sizeof(mac));
|
|
return 0;
|
|
}
|
|
|
|
void rwnx_platform_custom_msg_vnet_init(void)
|
|
{
|
|
g_custom_msg_vnet.aic_mode_status = AIC_MODE_IDLE;
|
|
g_custom_msg_vnet.wlan_status = WLAN_DISCONNECT;
|
|
g_custom_msg_vnet.ap_status = AIC_AP_CLOSE;
|
|
g_custom_msg_vnet.comp_sign_get_mac_ready = false;
|
|
g_custom_msg_vnet.comp_sign_get_wlan_ready = false;
|
|
g_custom_msg_vnet.scan_wifi_cfm_ptr = NULL;
|
|
}
|
|
|
|
void rwnx_platform_get_mac_ready(void)
|
|
{
|
|
complete(&g_custom_msg_vnet.platform_get_mac_done);
|
|
}
|
|
int rwnx_platform_get_mac_addr(void)
|
|
{
|
|
struct custom_msg_hdr req;
|
|
req.cmd_id = CUST_CMD_GET_MAC_ADDR_REQ;
|
|
|
|
// To avoid complete platform_get_mac_done before init_completion
|
|
init_completion(&g_custom_msg_vnet.platform_get_mac_done);
|
|
rwnx_tx_msg( (u8 *)&req, sizeof(req));
|
|
|
|
//init_completion(&platform_get_mac_done);
|
|
if ((wait_for_completion_timeout(&g_custom_msg_vnet.platform_get_mac_done,
|
|
msecs_to_jiffies(PLATFORM_PREPARE_TIMEOUT)) == 0)) {
|
|
printk("error: platform get mac address timeout\n");
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void rwnx_platform_get_wlan_ready(void)
|
|
{
|
|
complete(&g_custom_msg_vnet.platform_get_wlan_done);
|
|
}
|
|
int rwnx_platform_get_wlan_status(void)
|
|
{
|
|
struct custom_msg_hdr req = {0};
|
|
req.cmd_id = CUST_CMD_GET_WLAN_STATUS_REQ;
|
|
|
|
// To avoid complete platform_get_conn_st_done before init_completion
|
|
init_completion(&g_custom_msg_vnet.platform_get_wlan_done);
|
|
rwnx_tx_msg( (u8 *)&req, sizeof(req));
|
|
|
|
//init_completion(&platform_get_mac_done);
|
|
if ((wait_for_completion_timeout(&g_custom_msg_vnet.platform_get_wlan_done,
|
|
msecs_to_jiffies(PLATFORM_PREPARE_TIMEOUT)) == 0)) {
|
|
printk("error: platform get wlan status timeout\n");
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* rwnx_platform_reset() - Reset the platform
|
|
*
|
|
* @rwnx_plat: platform data
|
|
*/
|
|
static int rwnx_platform_reset(struct rwnx_plat *rwnx_plat)
|
|
{
|
|
u32 regval;
|
|
|
|
#if defined(AICWF_USB_SUPPORT) || defined(AICWF_SDIO_SUPPORT)
|
|
return 0;
|
|
#endif
|
|
|
|
/* the doc states that SOFT implies FPGA_B_RESET
|
|
* adding FPGA_B_RESET is clearer */
|
|
RWNX_REG_WRITE(SOFT_RESET | FPGA_B_RESET, rwnx_plat,
|
|
RWNX_ADDR_SYSTEM, SYSCTRL_MISC_CNTL_ADDR);
|
|
msleep(100);
|
|
|
|
regval = RWNX_REG_READ(rwnx_plat, RWNX_ADDR_SYSTEM, SYSCTRL_MISC_CNTL_ADDR);
|
|
|
|
if (regval & SOFT_RESET) {
|
|
dev_err(rwnx_platform_get_dev(rwnx_plat), "reset: failed\n");
|
|
return -EIO;
|
|
}
|
|
|
|
RWNX_REG_WRITE(regval & ~FPGA_B_RESET, rwnx_plat,
|
|
RWNX_ADDR_SYSTEM, SYSCTRL_MISC_CNTL_ADDR);
|
|
msleep(100);
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* rwmx_platform_save_config() - Save hardware config before reload
|
|
*
|
|
* @rwnx_plat: Pointer to platform data
|
|
*
|
|
* Return configuration registers values.
|
|
*/
|
|
static void* rwnx_term_save_config(struct rwnx_plat *rwnx_plat)
|
|
{
|
|
const u32 *reg_list;
|
|
u32 *reg_value, *res;
|
|
int i, size = 0;
|
|
|
|
if (rwnx_plat->get_config_reg) {
|
|
size = rwnx_plat->get_config_reg(rwnx_plat, ®_list);
|
|
}
|
|
|
|
if (size <= 0)
|
|
return NULL;
|
|
|
|
res = kmalloc(sizeof(u32) * size, GFP_KERNEL);
|
|
if (!res)
|
|
return NULL;
|
|
|
|
reg_value = res;
|
|
for (i = 0; i < size; i++) {
|
|
*reg_value++ = RWNX_REG_READ(rwnx_plat, RWNX_ADDR_SYSTEM, *reg_list++);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
/**
|
|
* rwnx_platform_on() - Start the platform
|
|
*
|
|
* @rwnx_hw: Main driver data
|
|
* @config: Config to restore (NULL if nothing to restore)
|
|
*
|
|
* It starts the platform :
|
|
* - load fw and ucodes
|
|
* - initialize IPC
|
|
* - boot the fw
|
|
* - enable link communication/IRQ
|
|
*
|
|
* Called by 802.11 part
|
|
*/
|
|
int rwnx_platform_on(struct rwnx_hw *rwnx_hw, void *config)
|
|
{
|
|
#if 0
|
|
u8 *shared_ram;
|
|
#endif
|
|
#ifndef CONFIG_ROM_PATCH_EN
|
|
#ifdef CONFIG_DOWNLOAD_FW
|
|
int ret;
|
|
#endif
|
|
#endif
|
|
struct rwnx_plat *rwnx_plat = rwnx_hw->plat;
|
|
|
|
RWNX_DBG(RWNX_FN_ENTRY_STR);
|
|
|
|
if (rwnx_plat->enabled)
|
|
return 0;
|
|
|
|
rwnx_plat->enabled = true;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* rwnx_platform_off() - Stop the platform
|
|
*
|
|
* @rwnx_hw: Main driver data
|
|
* @config: Updated with pointer to config, to be able to restore it with
|
|
* rwnx_platform_on(). It's up to the caller to free the config. Set to NULL
|
|
* if configuration is not needed.
|
|
*
|
|
* Called by 802.11 part
|
|
*/
|
|
void rwnx_platform_off(struct rwnx_hw *rwnx_hw, void **config)
|
|
{
|
|
#if defined(AICWF_USB_SUPPORT) || defined(AICWF_SDIO_SUPPORT)
|
|
rwnx_hw->plat->enabled = false;
|
|
return ;
|
|
#endif
|
|
|
|
if (!rwnx_hw->plat->enabled) {
|
|
if (config)
|
|
*config = NULL;
|
|
return;
|
|
}
|
|
|
|
if (config)
|
|
*config = rwnx_term_save_config(rwnx_hw->plat);
|
|
|
|
rwnx_hw->plat->disable(rwnx_hw);
|
|
|
|
tasklet_kill(&rwnx_hw->task);
|
|
|
|
rwnx_platform_reset(rwnx_hw->plat);
|
|
|
|
rwnx_hw->plat->enabled = false;
|
|
}
|
|
|
|
#ifdef CONFIG_APP_FASYNC
|
|
struct rwnx_aic_chardev chardev;
|
|
int rwnx_aic_cdev_open(struct inode *inode, struct file *filp)
|
|
{
|
|
filp->private_data = &chardev;
|
|
printk("rwnx_aic_cdev_open\r\n");
|
|
return 0;
|
|
}
|
|
|
|
ssize_t rwnx_aic_cdev_read(struct file* filp, char __user* buf, size_t cnt, loff_t* f_pos)
|
|
{
|
|
struct rwnx_aic_chardev *pchardev = filp->private_data;
|
|
printk("rwnx_aic_cdev_read\r\n");
|
|
//rk fix if(copy_to_user(buf, pchardev->mem, cnt) < 0) {
|
|
if(copy_to_user(buf, pchardev->mem, cnt)) {
|
|
printk("copy kernel data fail\n");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int rwnx_aic_cdev_fasync(int fd, struct file *filp, int on)
|
|
{
|
|
struct rwnx_aic_chardev *pchardev = filp->private_data;
|
|
fasync_helper(fd, filp, on, &pchardev->async_queue);
|
|
printk("rwnx_aic_cdev_fasync\r\n");
|
|
return 0;
|
|
}
|
|
|
|
int rwnx_aic_cdev_release(struct inode* inode, struct file* filp)
|
|
{
|
|
rwnx_aic_cdev_fasync(-1, filp, 0);
|
|
printk("rwnx_aic_cdev_release\r\n");
|
|
return 0;
|
|
}
|
|
|
|
static struct file_operations aic_cdev_driver_fops = {
|
|
.owner = THIS_MODULE,
|
|
.open = rwnx_aic_cdev_open,
|
|
.read = rwnx_aic_cdev_read,
|
|
.fasync = rwnx_aic_cdev_fasync,
|
|
.release = rwnx_aic_cdev_release,
|
|
};
|
|
|
|
int rwnx_aic_cdev_driver_init(void)
|
|
{
|
|
int ret = 0;
|
|
struct device *devices;
|
|
if (alloc_chrdev_region(&chardev.dev, 0, 1, "aic_cdev_ioctl")) {
|
|
printk("%s: alloc_chrdev_region failure\n", __FUNCTION__);
|
|
goto exit;
|
|
}
|
|
chardev.major = MAJOR(chardev.dev);
|
|
|
|
// add cdev
|
|
chardev.c_cdev = kzalloc(sizeof(struct cdev), GFP_KERNEL);
|
|
if(IS_ERR(chardev.c_cdev)) {
|
|
printk("%s: kmalloc failure\n", __FUNCTION__);
|
|
ret = PTR_ERR(chardev.c_cdev);
|
|
goto free_chrdev_region;
|
|
}
|
|
cdev_init(chardev.c_cdev, &aic_cdev_driver_fops);
|
|
ret = cdev_add(chardev.c_cdev, chardev.dev, 1);
|
|
if(ret < 0) {
|
|
printk("%s: cdev_add failure\n", __FUNCTION__);
|
|
goto free_chrdev_region;
|
|
}
|
|
|
|
// create device_class
|
|
chardev.cdev_class = class_create(THIS_MODULE, "aic_cdev_class");
|
|
if(IS_ERR(chardev.cdev_class)) {
|
|
printk("%s: class_create failure\n", __FUNCTION__);
|
|
ret = PTR_ERR(chardev.cdev_class);
|
|
goto free_cdev;
|
|
}
|
|
|
|
// create device
|
|
devices = device_create(chardev.cdev_class, NULL, MKDEV(chardev.major,0), NULL, "aic_cdev");
|
|
if(IS_ERR(devices)) {
|
|
printk("%s: device_create failure\n", __FUNCTION__);
|
|
ret = PTR_ERR(devices);
|
|
goto free_device_class;
|
|
}
|
|
|
|
printk("Create device: /dev/aic_cdev_class\n");
|
|
return 0;
|
|
|
|
free_device_class:
|
|
class_destroy(chardev.cdev_class);
|
|
free_cdev:
|
|
cdev_del(chardev.c_cdev);
|
|
free_chrdev_region:
|
|
unregister_chrdev_region(chardev.dev, 1);
|
|
exit:
|
|
return ret;
|
|
}
|
|
|
|
void rwnx_aic_cdev_driver_deinit(void)
|
|
{
|
|
printk("%s\n",__FUNCTION__);
|
|
|
|
device_destroy(chardev.cdev_class, MKDEV(chardev.major,0));
|
|
class_destroy(chardev.cdev_class);
|
|
|
|
cdev_del(chardev.c_cdev);
|
|
unregister_chrdev_region(chardev.dev, 1);
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* rwnx_platform_init() - Initialize the platform
|
|
*
|
|
* @rwnx_plat: platform data (already updated by platform driver)
|
|
* @platform_data: Pointer to store the main driver data pointer (aka rwnx_hw)
|
|
* That will be set as driver data for the platform driver
|
|
* Return: 0 on success, < 0 otherwise
|
|
*
|
|
* Called by the platform driver after it has been probed
|
|
*/
|
|
int rwnx_platform_init(struct rwnx_plat *rwnx_plat, void **platform_data)
|
|
{
|
|
RWNX_DBG(RWNX_FN_ENTRY_STR);
|
|
|
|
rwnx_plat->enabled = true;
|
|
g_rwnx_plat = rwnx_plat;
|
|
|
|
#ifdef CONFIG_VNET_MODE
|
|
rwnx_platform_custom_msg_vnet_init();
|
|
if(rwnx_platform_get_wlan_status() != 0)
|
|
return -1;
|
|
#ifndef CONFIG_FAST_INSMOD
|
|
if(rwnx_platform_get_mac_addr() != 0)
|
|
return -1;
|
|
#endif
|
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)
|
|
memcpy(g_rwnx_vif.wdev.address, g_custom_msg_vnet.macaddr_cfm.mac_addr, 6);
|
|
#else
|
|
memcpy(g_rwnx_vif.address, g_custom_msg_vnet.macaddr_cfm.mac_addr, 6);
|
|
#endif
|
|
if(virt_net_init(&g_rwnx_vif)) {
|
|
printk("vnet_dev init fail.\n");
|
|
return -1;
|
|
}
|
|
|
|
#ifdef CONFIG_APP_FASYNC
|
|
rwnx_aic_cdev_driver_init();
|
|
#endif
|
|
|
|
#elif defined(CONFIG_RAWDATA_MODE)
|
|
rwnx_nlaic_init(rwnx_plat, platform_data);
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* rwnx_platform_deinit() - Deinitialize the platform
|
|
*
|
|
* @rwnx_hw: main driver data
|
|
*
|
|
* Called by the platform driver after it is removed
|
|
*/
|
|
void rwnx_platform_deinit(void)
|
|
{
|
|
RWNX_DBG(RWNX_FN_ENTRY_STR);
|
|
#ifdef CONFIG_VNET_MODE
|
|
virt_net_exit();
|
|
|
|
#ifdef CONFIG_APP_FASYNC
|
|
rwnx_aic_cdev_driver_deinit();
|
|
#endif
|
|
|
|
#elif defined(CONFIG_RAWDATA_MODE)
|
|
rwnx_nlaic_deinit();
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* rwnx_platform_register_drv() - Register all possible platform drivers
|
|
*/
|
|
int rwnx_platform_register_drv(void)
|
|
{
|
|
return 0;//rwnx_pci_register_drv();
|
|
}
|
|
|
|
|
|
/**
|
|
* rwnx_platform_unregister_drv() - Unegister all platform drivers
|
|
*/
|
|
void rwnx_platform_unregister_drv(void)
|
|
{
|
|
//return rwnx_pci_unregister_drv();
|
|
}
|
|
|
|
struct device *rwnx_platform_get_dev(struct rwnx_plat *rwnx_plat)
|
|
{
|
|
#ifdef AICWF_SDIO_SUPPORT
|
|
return rwnx_plat->sdiodev->dev;
|
|
#endif
|
|
#ifdef AICWF_USB_SUPPORT
|
|
return rwnx_plat->usbdev->dev;
|
|
#endif
|
|
return &(rwnx_plat->pci_dev->dev);
|
|
}
|
|
|
|
#ifndef CONFIG_RWNX_SDM
|
|
MODULE_FIRMWARE(RWNX_AGC_FW_NAME);
|
|
MODULE_FIRMWARE(RWNX_FCU_FW_NAME);
|
|
MODULE_FIRMWARE(RWNX_LDPC_RAM_NAME);
|
|
#endif
|
|
MODULE_FIRMWARE(RWNX_MAC_FW_NAME);
|
|
#ifndef CONFIG_RWNX_TL4
|
|
MODULE_FIRMWARE(RWNX_MAC_FW_NAME2);
|
|
#endif
|
|
|