fix: harden ch390 recovery primitives

This commit is contained in:
2026-04-23 18:06:03 +08:00
parent d6a1565503
commit c519f90149
2 changed files with 96 additions and 3 deletions
+81 -3
View File
@@ -12,6 +12,25 @@
#include "CH390.h" #include "CH390.h"
#include "CH390_Interface.h" #include "CH390_Interface.h"
#define CH390_EPCR_POLL_LIMIT 100000u
static int ch390_wait_epcr_ready(void)
{
uint32_t poll_count = CH390_EPCR_POLL_LIMIT;
while ((ch390_read_reg(CH390_EPCR) & 0x01u) != 0u)
{
if (poll_count == 0u)
{
ch390_write_reg(CH390_EPCR, 0x00u);
return -1;
}
--poll_count;
}
return 0;
}
void ch390_probe_rx_header(uint8_t *head) void ch390_probe_rx_header(uint8_t *head)
{ {
if (head == 0) if (head == 0)
@@ -22,6 +41,46 @@ void ch390_probe_rx_header(uint8_t *head)
ch390_read_mem(head, 4); ch390_read_mem(head, 4);
} }
int ch390_peek_packet(uint8_t *rx_status, uint16_t *rx_len)
{
uint8_t nsr;
uint8_t header[4];
uint16_t mrr;
if (rx_status != 0)
{
*rx_status = 0u;
}
if (rx_len != 0)
{
*rx_len = 0u;
}
nsr = ch390_read_reg(CH390_NSR);
if ((nsr & NSR_RXRDY) == 0u)
{
return 0;
}
mrr = (uint16_t)ch390_read_mrrl() | ((uint16_t)ch390_read_mrrh() << 8);
ch390_read_mem(header, 4);
ch390_write_reg(CH390_MRRL, (uint8_t)(mrr & 0xffu));
ch390_write_reg(CH390_MRRH, (uint8_t)((mrr >> 8) & 0xffu));
if (rx_status != 0)
{
*rx_status = header[1];
}
if (rx_len != 0)
{
*rx_len = (uint16_t)header[2] | ((uint16_t)header[3] << 8);
}
return 1;
}
/** /**
* @name ch390_receive_packet * @name ch390_receive_packet
* @brief Receive packet * @brief Receive packet
@@ -125,6 +184,16 @@ void ch390_drop_packet(uint16_t len)
ch390_write_reg(CH390_MRRH, (mdr >> 8) & 0xff); ch390_write_reg(CH390_MRRH, (mdr >> 8) & 0xff);
} }
void ch390_rx_reset(void)
{
uint8_t rcr = ch390_read_reg(CH390_RCR);
ch390_write_reg(CH390_RCR, (uint8_t)(rcr & (uint8_t)(~RCR_RXEN)));
ch390_write_reg(CH390_NSR, NSR_RXOV);
ch390_write_reg(CH390_ISR, (uint8_t)(ISR_ROS | ISR_ROO | ISR_PR));
ch390_write_reg(CH390_RCR, (uint8_t)(rcr | RCR_RXEN));
}
/** /**
* @name ch390_read_phy * @name ch390_read_phy
* @brief Read PHY register * @brief Read PHY register
@@ -135,7 +204,10 @@ uint16_t ch390_read_phy(uint8_t reg)
ch390_write_reg(CH390_EPAR, CH390_PHY | reg); ch390_write_reg(CH390_EPAR, CH390_PHY | reg);
// Chose PHY, send read command // Chose PHY, send read command
ch390_write_reg(CH390_EPCR, EPCR_ERPRR | EPCR_EPOS); ch390_write_reg(CH390_EPCR, EPCR_ERPRR | EPCR_EPOS);
while(ch390_read_reg(CH390_EPCR) & 0x01); if (ch390_wait_epcr_ready() != 0)
{
return 0xFFFFu;
}
// Clear read command // Clear read command
ch390_write_reg(CH390_EPCR, 0x00); ch390_write_reg(CH390_EPCR, 0x00);
return (ch390_read_reg(CH390_EPDRH) << 8) | return (ch390_read_reg(CH390_EPDRH) << 8) |
@@ -155,7 +227,10 @@ void ch390_write_phy(uint8_t reg, uint16_t value)
ch390_write_reg(CH390_EPDRH, ((value >> 8) & 0xff)); // High byte ch390_write_reg(CH390_EPDRH, ((value >> 8) & 0xff)); // High byte
// Chose PHY, send write command // Chose PHY, send write command
ch390_write_reg(CH390_EPCR, 0x0A); ch390_write_reg(CH390_EPCR, 0x0A);
while(ch390_read_reg(CH390_EPCR) & 0x01); if (ch390_wait_epcr_ready() != 0)
{
return;
}
// Clear write command // Clear write command
ch390_write_reg(CH390_EPCR, 0x00); ch390_write_reg(CH390_EPCR, 0x00);
} }
@@ -173,7 +248,10 @@ void ch390_write_eeprom(uint8_t reg, uint16_t value)
ch390_write_reg(CH390_EPDRH, ((value >> 8) & 0xff)); // High byte ch390_write_reg(CH390_EPDRH, ((value >> 8) & 0xff)); // High byte
// Chose EEPROM, send write command // Chose EEPROM, send write command
ch390_write_reg(CH390_EPCR, EPCR_ERPRW); ch390_write_reg(CH390_EPCR, EPCR_ERPRW);
while(ch390_read_reg(CH390_EPCR) & 0x01); if (ch390_wait_epcr_ready() != 0)
{
return;
}
// Clear write command // Clear write command
ch390_write_reg(CH390_EPCR, 0x00); ch390_write_reg(CH390_EPCR, 0x00);
} }
+15
View File
@@ -657,6 +657,21 @@ int ch390_runtime_link_up_from_status(const struct ch390_runtime_status *status)
*/ */
void ch390_probe_rx_header(uint8_t *head); void ch390_probe_rx_header(uint8_t *head);
/**
* @name ch390_peek_packet
* @brief Peek current RX header without consuming the packet.
* @param rx_status - Output abnormal status while receiving packet
* @param rx_len - Output packet length from RX header
* @return 0: no packet pending 1: header sampled
*/
int ch390_peek_packet(uint8_t *rx_status, uint16_t *rx_len);
/**
* @name ch390_rx_reset
* @brief Repair RX datapath after overflow/corruption without full chip reset.
*/
void ch390_rx_reset(void);
/** /**
* @name ch390_runtime_receive_packet * @name ch390_runtime_receive_packet
* @brief Runtime RX entry point for packet receive * @brief Runtime RX entry point for packet receive