fix: harden ch390 recovery primitives
This commit is contained in:
+81
-3
@@ -12,6 +12,25 @@
|
||||
#include "CH390.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)
|
||||
{
|
||||
if (head == 0)
|
||||
@@ -22,6 +41,46 @@ void ch390_probe_rx_header(uint8_t *head)
|
||||
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
|
||||
* @brief Receive packet
|
||||
@@ -125,6 +184,16 @@ void ch390_drop_packet(uint16_t len)
|
||||
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
|
||||
* @brief Read PHY register
|
||||
@@ -135,7 +204,10 @@ uint16_t ch390_read_phy(uint8_t reg)
|
||||
ch390_write_reg(CH390_EPAR, CH390_PHY | reg);
|
||||
// Chose PHY, send read command
|
||||
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
|
||||
ch390_write_reg(CH390_EPCR, 0x00);
|
||||
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
|
||||
// Chose PHY, send write command
|
||||
ch390_write_reg(CH390_EPCR, 0x0A);
|
||||
while(ch390_read_reg(CH390_EPCR) & 0x01);
|
||||
if (ch390_wait_epcr_ready() != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Clear write command
|
||||
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
|
||||
// Chose EEPROM, send write command
|
||||
ch390_write_reg(CH390_EPCR, EPCR_ERPRW);
|
||||
while(ch390_read_reg(CH390_EPCR) & 0x01);
|
||||
if (ch390_wait_epcr_ready() != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Clear write command
|
||||
ch390_write_reg(CH390_EPCR, 0x00);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
/**
|
||||
* @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
|
||||
* @brief Runtime RX entry point for packet receive
|
||||
|
||||
Reference in New Issue
Block a user