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>
This commit is contained in:
luckfox-eng29
2024-08-21 10:05:47 +08:00
parent e79fd21975
commit 8f34c2760d
20902 changed files with 6567362 additions and 11248383 deletions

View File

@@ -20,6 +20,7 @@
#include <linux/of_irq.h>
#include <linux/phy.h>
#include <linux/platform_device.h>
#include <linux/thermal.h>
#include <linux/wakelock.h>
#define RK630_PHY_ID 0x00441400
@@ -71,6 +72,39 @@
#define T22_TX_LEVEL_100M 0x2d
#define T22_TX_LEVEL_10M 0x32
/* Long network cable parameters */
#define RX_DETECT_SCHEDULE_TIME 500 /* ms */
#define RX_DETECT_INIT_WAIT_TIME 2000 /* ms */
#define RX_DETECT_MAX_COUNT (5000 / RX_DETECT_SCHEDULE_TIME)
#define ALL_RX_DETECT_MAX_COUNT (2 * RX_DETECT_MAX_COUNT)
#define LINKED_MAX_COUNT (10000 / RX_DETECT_SCHEDULE_TIME)
#define ALL_LINKED_MAX_COUNT (2 * LINKED_MAX_COUNT)
#define RX_PACKET_RECEIVED_COUNTS 3 /* packets */
#define RX_PACKET_RECEIVED_LOST 15 /* percent */
#define RX_SIGNAL_DETECT_TEMP 85000
struct rk630_phy_switched {
/* record state */
bool config;
bool config_mode_10M;
bool finished;
/* detected process */
unsigned int detected_count;
bool config_rx_signal;
int old_link;
/* linked process */
unsigned int linked_count;
int rx_pkt_cnt;
int rx_crc_err_cnt;
int lost_percent;
};
struct rk630_phy_priv {
struct phy_device *phydev;
bool ieee;
@@ -78,6 +112,13 @@ struct rk630_phy_priv {
struct wake_lock wol_wake_lock;
int tx_level_100M;
int tx_level_10M;
struct rk630_phy_switched switched;
/* mutex protect variables between notify thread and delayed work */
struct mutex lock;
struct delayed_work service_task;
struct thermal_zone_device *tz;
bool disable_switch;
};
static void rk630_phy_t22_get_tx_level_from_efuse(struct phy_device *phydev)
@@ -160,19 +201,49 @@ static void rk630_phy_ieee_set(struct phy_device *phydev, bool enable)
phy_write(phydev, REG_PAGE_SEL, 0x0000);
}
static void rk630_phy_set_uaps(struct phy_device *phydev)
static void rk630_phy_set_aps(struct phy_device *phydev, bool enable)
{
u32 value;
/* Switch to page 1 */
phy_write(phydev, REG_PAGE_SEL, 0x0100);
value = phy_read(phydev, REG_PAGE1_APS_CTRL);
if (enable)
value |= BIT(15);
else
value &= ~BIT(15);
phy_write(phydev, REG_PAGE1_APS_CTRL, value);
/* Switch to page 0 */
phy_write(phydev, REG_PAGE_SEL, 0x0000);
}
static void rk630_phy_set_uaps(struct phy_device *phydev, bool enable)
{
u32 value;
/* Switch to page 1 */
phy_write(phydev, REG_PAGE_SEL, 0x0100);
value = phy_read(phydev, REG_PAGE1_UAPS_CONFIGURE);
value |= BIT(15);
if (enable)
value |= BIT(15);
else
value &= ~BIT(15);
phy_write(phydev, REG_PAGE1_UAPS_CONFIGURE, value);
/* Switch to page 0 */
phy_write(phydev, REG_PAGE_SEL, 0x0000);
}
static bool rk630_phy_rx_signal_detected(struct phy_device *phydev)
{
u32 value;
/* Switch to page 0 */
phy_write(phydev, REG_PAGE_SEL, 0x0000);
value = phy_read(phydev, 25);
return (value & BIT(15)) ? false : true;
}
static void rk630_phy_s40_config_init(struct phy_device *phydev)
{
phy_write(phydev, 0, phy_read(phydev, 0) & ~BIT(13));
@@ -210,8 +281,8 @@ static void rk630_phy_t22_config_init(struct phy_device *phydev)
phy_write(phydev, REG_PAGE_SEL, 0x0100);
/* Enable offset clock */
phy_write(phydev, 0x10, 0xfbfe);
/* Disable APS */
phy_write(phydev, REG_PAGE1_APS_CTRL, 0x4824);
/* Disable APS & Rx detected time 2s, default is 4s */
phy_write(phydev, REG_PAGE1_APS_CTRL, 0x4822);
/* Switch to page 2 */
phy_write(phydev, REG_PAGE_SEL, 0x0200);
/* PHYAFE TRX optimization */
@@ -223,7 +294,15 @@ static void rk630_phy_t22_config_init(struct phy_device *phydev)
/* PHYAFE Gain optimization */
phy_write(phydev, REG_PAGE6_GAIN_ANONTROL, 0x0400);
/* PHYAFE EQ optimization */
phy_write(phydev, REG_PAGE6_AFE_TX_CTRL, 0x1088);
if (priv->disable_switch) {
/* Rx detected default threshold 160 mv */
phy_write(phydev, REG_PAGE6_AFE_TX_CTRL, 0x1088);
} else {
/* Rx detected threshold 260 mv */
phy_write(phydev, REG_PAGE6_AFE_TX_CTRL, 0x10c8);
priv->switched.config_rx_signal = true;
}
if (priv->tx_level_100M <= 0 || priv->tx_level_10M <= 0)
rk630_phy_t22_get_tx_level_from_efuse(phydev);
@@ -268,10 +347,12 @@ static int rk630_phy_config_init(struct phy_device *phydev)
* Ultra Auto-Power Saving Mode (UAPS) is designed to
* save power when cable is not plugged into PHY.
*/
rk630_phy_set_uaps(phydev);
rk630_phy_set_uaps(phydev, true);
break;
case PHY_ADDR_T22:
rk630_phy_t22_config_init(phydev);
rk630_phy_set_aps(phydev, false);
rk630_phy_set_uaps(phydev, false);
break;
default:
phydev_err(phydev, "Unsupported address for current phy: %d\n",
@@ -284,6 +365,305 @@ static int rk630_phy_config_init(struct phy_device *phydev)
return 0;
}
/* config0(default) and config1(0x555e) switched for 100/10M speed */
static bool rk630_phy_switch_config(struct phy_device *phydev, bool config)
{
struct rk630_phy_priv *priv = phydev->priv;
if (priv->switched.config != config) {
int val;
val = config ? 0x555e : 0x5540;
phy_write(priv->phydev, REG_PAGE_SEL, 0x0600);
phy_write(priv->phydev, REG_PAGE6_ADC_ANONTROL, val);
phy_write(priv->phydev, REG_PAGE_SEL, 0x0000);
priv->switched.config = config;
return true;
}
return false;
}
/* 10M speed configuration */
static void rk630_phy_10m_switch_config(struct phy_device *phydev, bool config)
{
struct rk630_phy_priv *priv = phydev->priv;
unsigned int val;
if (config == priv->switched.config_mode_10M)
return;
phy_write(phydev, REG_PAGE_SEL, 0x0600);
val = phy_read(phydev, REG_PAGE6_AFE_TX_CTRL);
val &= ~GENMASK(14, 13);
if (config && !priv->switched.config_mode_10M)
val |= BIT(13);
priv->switched.config_mode_10M = config;
phy_write(phydev, REG_PAGE6_AFE_TX_CTRL, val);
phy_write(priv->phydev, REG_PAGE_SEL, 0x0000);
}
static void rk630_phy_switch_rx_signal_config(struct phy_device *phydev,
bool config)
{
struct rk630_phy_priv *priv = phydev->priv;
if (priv->switched.config_rx_signal != config) {
int val;
phy_write(priv->phydev, REG_PAGE_SEL, 0x0600);
val = phy_read(phydev, REG_PAGE6_AFE_TX_CTRL);
val &= ~GENMASK(7, 6);
if (config)
val |= GENMASK(7, 6);
else
val |= BIT(7);
phy_write(phydev, REG_PAGE6_AFE_TX_CTRL, val);
phy_write(priv->phydev, REG_PAGE_SEL, 0x0000);
priv->switched.config_rx_signal = config;
}
}
static void rk630_phy_packet_statistics(struct phy_device *phydev,
int *total_cnt, int *crc_err_cnt)
{
struct rk630_phy_priv *priv = phydev->priv;
phy_write(priv->phydev, REG_PAGE_SEL, 0x0900);
*total_cnt = phy_read(priv->phydev, 0x1b) << 16;
*total_cnt |= phy_read(priv->phydev, 0x1c);
*crc_err_cnt = phy_read(priv->phydev, 0x1d) << 16;
*crc_err_cnt |= phy_read(priv->phydev, 0x1e);
phy_write(phydev, REG_PAGE_SEL, 0x0000);
}
static bool rk630_phy_switch_config_by_packets(struct phy_device *phydev)
{
struct rk630_phy_priv *priv = phydev->priv;
int rx_pkt_cnt, rx_crc_err_cnt;
int total_cnt, total_crc_err_cnt;
int lost_percent;
rk630_phy_packet_statistics(phydev, &total_cnt, &total_crc_err_cnt);
rx_pkt_cnt = total_cnt - priv->switched.rx_pkt_cnt;
rx_crc_err_cnt = total_crc_err_cnt - priv->switched.rx_crc_err_cnt;
priv->switched.rx_pkt_cnt = total_cnt;
priv->switched.rx_crc_err_cnt = total_crc_err_cnt;
/* less than the minimal received packets during some time */
if (rx_pkt_cnt < RX_PACKET_RECEIVED_COUNTS)
return true;
/* Percents packets lost is not good during some time */
lost_percent = (rx_crc_err_cnt * 100 / rx_pkt_cnt) > RX_PACKET_RECEIVED_LOST;
/* Just compare with config0's packet lost, update config if it is better
* than config0.
*/
if (((rx_crc_err_cnt * 100 / rx_pkt_cnt) > RX_PACKET_RECEIVED_LOST) &&
lost_percent > priv->switched.lost_percent) {
/* Only save config0 lost percent */
if (!priv->switched.config)
priv->switched.lost_percent = lost_percent;
return true;
}
/* Only save config0 lost percent */
if (!priv->switched.config)
priv->switched.lost_percent = lost_percent;
return false;
}
static void rk630_phy_service_task(struct work_struct *work)
{
struct rk630_phy_priv *priv = container_of(work, struct rk630_phy_priv,
service_task.work);
unsigned int delay_time;
int ret, temp;
mutex_lock(&priv->lock);
if (priv->disable_switch) {
mutex_unlock(&priv->lock);
return;
}
if (!priv->phydev->link) {
bool signal_detected;
signal_detected = rk630_phy_rx_signal_detected(priv->phydev);
/* Read signal */
if (!signal_detected) {
/* Slow schedule work for 2 * SCHEDULE_TIME, if no signal */
priv->switched.detected_count = 0;
priv->switched.lost_percent = 0;
priv->switched.finished = false;
priv->switched.linked_count = 0;
delay_time = 2 * RX_DETECT_SCHEDULE_TIME;
/* Goto default config if no rj45 signal plugin */
rk630_phy_switch_config(priv->phydev, false);
/* Also go to 10M default config */
rk630_phy_10m_switch_config(priv->phydev, false);
} else {
priv->switched.detected_count++;
/* Fast schedule work for 1 * SCHEDULE_TIME, if signal
* detected.
*/
delay_time = RX_DETECT_SCHEDULE_TIME;
if (priv->switched.detected_count == RX_DETECT_MAX_COUNT &&
!priv->switched.finished) {
/* After it, there is no link, Might be a long cable,
* config1 switched to get better performance during
* some time.
*/
rk630_phy_switch_config(priv->phydev, true);
} else if (priv->switched.detected_count == ALL_RX_DETECT_MAX_COUNT &&
!priv->switched.finished) {
/* After another detect, we lost the last chance,
* go back to default config0.
*/
rk630_phy_switch_config(priv->phydev, false);
priv->switched.finished = true;
} else if (priv->switched.detected_count > ALL_RX_DETECT_MAX_COUNT ||
priv->switched.finished) {
/* Slow schedule work for 2 * SCHEDULE_TIME, if
* detected finish.
*/
delay_time = 2 * RX_DETECT_SCHEDULE_TIME;
}
}
} else {
/* Detect the packet count and crc error count statistics */
priv->switched.linked_count++;
/* Fast schedule work for 1 * SCHEDULE_TIME, if linkup detected */
delay_time = RX_DETECT_SCHEDULE_TIME;
if (priv->switched.linked_count == LINKED_MAX_COUNT &&
!priv->switched.finished) {
if (rk630_phy_switch_config_by_packets(priv->phydev)) {
/* Config1 switched to get better performance */
rk630_phy_switch_config(priv->phydev, true);
/* Also go to 10M default config */
if (priv->switched.config && priv->phydev->speed == SPEED_10)
rk630_phy_10m_switch_config(priv->phydev, true);
}
} else if (priv->switched.linked_count == ALL_LINKED_MAX_COUNT &&
!priv->switched.finished) {
/* If config switched, we lost the last chance, return to
* default config0.
*/
if (rk630_phy_switch_config_by_packets(priv->phydev)) {
rk630_phy_switch_config(priv->phydev, false);
rk630_phy_10m_switch_config(priv->phydev, false);
}
priv->switched.finished = true;
} else if (priv->switched.linked_count > ALL_LINKED_MAX_COUNT ||
priv->switched.finished) {
/* Slow schedule work for 2 * SCHEDULE_TIME, if linkup
* detected finish.
*/
delay_time = 2 * RX_DETECT_SCHEDULE_TIME;
}
}
if (priv->tz) {
ret = thermal_zone_get_temp(priv->tz, &temp);
if (ret || temp == THERMAL_TEMP_INVALID)
phydev_err(priv->phydev,
"failed to read out thermal zone (%d)\n", ret);
else
rk630_phy_switch_rx_signal_config(priv->phydev,
(temp > RX_SIGNAL_DETECT_TEMP) ? false : true);
}
schedule_delayed_work(&priv->service_task, msecs_to_jiffies(delay_time));
mutex_unlock(&priv->lock);
}
static void rk630_phy_link_change_notify(struct phy_device *phydev)
{
struct rk630_phy_priv *priv = phydev->priv;
if (phydev->mdio.addr == PHY_ADDR_T22) {
mutex_lock(&priv->lock);
if (priv->disable_switch) {
mutex_unlock(&priv->lock);
return;
}
if (priv->switched.old_link && !phydev->link) {
priv->switched.old_link = 0;
priv->switched.linked_count = 0;
schedule_delayed_work(&priv->service_task,
msecs_to_jiffies(RX_DETECT_SCHEDULE_TIME));
} else if (!priv->switched.old_link && phydev->link) {
/* If linked, keep current config, but if the linked is
* 10M speed, and config1 has been enabled, also switched
* the 10M config.
*/
if (priv->switched.config && phydev->speed == SPEED_10)
rk630_phy_10m_switch_config(phydev, true);
priv->switched.old_link = 1;
priv->switched.detected_count = 0;
/* Record base packet statistics to compare later, if linked */
if (!priv->switched.linked_count)
rk630_phy_packet_statistics(priv->phydev,
&priv->switched.rx_pkt_cnt,
&priv->switched.rx_crc_err_cnt);
schedule_delayed_work(&priv->service_task,
msecs_to_jiffies(RX_DETECT_SCHEDULE_TIME));
}
mutex_unlock(&priv->lock);
}
}
static ssize_t rk630_phy_disable_switch_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct phy_device *phydev = to_phy_device(dev);
struct rk630_phy_priv *priv = phydev->priv;
int ret;
bool disabled;
ret = kstrtobool(buf, &disabled);
if (ret)
return count;
mutex_lock(&priv->lock);
if (disabled) {
cancel_delayed_work_sync(&priv->service_task);
/* Save to default config */
rk630_phy_10m_switch_config(priv->phydev, false);
rk630_phy_switch_rx_signal_config(priv->phydev, false);
rk630_phy_switch_config(priv->phydev, false);
memset(&priv->switched, 0, sizeof(struct rk630_phy_switched));
} else {
priv->switched.old_link = phydev->link;
/* Rx detected threshold 260 mv */
rk630_phy_switch_rx_signal_config(priv->phydev, true);
schedule_delayed_work(&priv->service_task,
msecs_to_jiffies(RX_DETECT_INIT_WAIT_TIME));
}
priv->disable_switch = disabled;
dev_info(dev, "rk630 phy disable switch to %s\n", disabled ? "true" : "false");
mutex_unlock(&priv->lock);
return count;
}
static DEVICE_ATTR_WO(rk630_phy_disable_switch);
static irqreturn_t rk630_wol_irq_thread(int irq, void *dev_id)
{
struct rk630_phy_priv *priv = (struct rk630_phy_priv *)dev_id;
@@ -296,6 +676,7 @@ static irqreturn_t rk630_wol_irq_thread(int irq, void *dev_id)
static int rk630_phy_probe(struct phy_device *phydev)
{
struct rk630_phy_priv *priv;
const char *tz_name;
int ret;
priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
@@ -324,6 +705,23 @@ static int rk630_phy_probe(struct phy_device *phydev)
enable_irq_wake(priv->wol_irq);
}
mutex_init(&priv->lock);
INIT_DELAYED_WORK(&priv->service_task, rk630_phy_service_task);
priv->disable_switch = of_property_read_bool(phydev->mdio.dev.of_node,
"rk630,phy-disable-switch");
of_property_read_string(phydev->mdio.dev.of_node, "rockchip,thermal-zone",
&tz_name);
priv->tz = thermal_zone_get_zone_by_name(tz_name);
if (IS_ERR(priv->tz)) {
pr_warn("Error getting thermal zone, not yet ready?\n");
priv->tz = NULL;
}
ret = device_create_file(&phydev->mdio.dev, &dev_attr_rk630_phy_disable_switch);
if (ret)
return ret;
priv->phydev = phydev;
return 0;
@@ -346,6 +744,10 @@ static int rk630_phy_suspend(struct phy_device *phydev)
phy_write(phydev, REG_INTERRUPT_MASK, BIT(14));
enable_irq(priv->wol_irq);
}
if (!priv->disable_switch)
cancel_delayed_work_sync(&priv->service_task);
return genphy_suspend(phydev);
}
@@ -359,6 +761,10 @@ static int rk630_phy_resume(struct phy_device *phydev)
disable_irq(priv->wol_irq);
}
if (!priv->disable_switch)
schedule_delayed_work(&priv->service_task,
msecs_to_jiffies(RX_DETECT_INIT_WAIT_TIME));
return genphy_resume(phydev);
}
@@ -369,6 +775,7 @@ static struct phy_driver rk630_phy_driver[] = {
.name = "RK630 PHY",
.features = PHY_BASIC_FEATURES,
.flags = 0,
.link_change_notify = rk630_phy_link_change_notify,
.probe = rk630_phy_probe,
.remove = rk630_phy_remove,
.soft_reset = genphy_soft_reset,
@@ -385,7 +792,7 @@ static struct mdio_device_id __maybe_unused rk630_phy_tbl[] = {
{ }
};
MODULE_DEVICE_TABLE(mdio, rockchip_phy_tbl);
MODULE_DEVICE_TABLE(mdio, rk630_phy_tbl);
module_phy_driver(rk630_phy_driver);