From 23fa18eaa71266feff7ba8d83022d9e1cc83c65a Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Fri, 10 May 2024 07:42:03 +0000 Subject: [PATCH] disable pwm7 --- kernel/drivers/net/can/rockchip/rockchip_canfd.c | 181 +++++++++++++++++++++++++++++++++++--------- 1 files changed, 143 insertions(+), 38 deletions(-) diff --git a/kernel/drivers/net/can/rockchip/rockchip_canfd.c b/kernel/drivers/net/can/rockchip/rockchip_canfd.c index a73c1f5..dba7f14 100644 --- a/kernel/drivers/net/can/rockchip/rockchip_canfd.c +++ b/kernel/drivers/net/can/rockchip/rockchip_canfd.c @@ -27,6 +27,7 @@ #include <linux/can/led.h> #include <linux/reset.h> #include <linux/pm_runtime.h> +#include <linux/rockchip/cpu.h> /* registers definition */ enum rockchip_canfd_reg { @@ -105,6 +106,7 @@ ROCKCHIP_CANFD_MODE = 0, ROCKCHIP_CAN_MODE, ROCKCHIP_RK3568_CAN_MODE, + ROCKCHIP_RK3568_CAN_MODE_V2, }; #define DATE_LENGTH_12_BYTE (0x9) @@ -212,6 +214,8 @@ #define CAN_RXFRD_OFFSET(n) (CAN_RXFRD + CAN_RF_SIZE * (n)) #define CAN_RX_FILTER_MASK 0x1fffffff +#define NOACK_ERR_FLAG 0xc200800 +#define CAN_BUSOFF_FLAG 0x20 #define DRV_NAME "rockchip_canfd" @@ -220,6 +224,7 @@ struct rockchip_canfd { struct can_priv can; struct device *dev; + struct napi_struct napi; struct clk_bulk_data *clks; int num_clks; struct reset_control *reset; @@ -231,6 +236,7 @@ bool txtorx; u32 tx_invalid[4]; struct delayed_work tx_err_work; + u32 delay_time_ms; }; static inline u32 rockchip_canfd_read(const struct rockchip_canfd *priv, @@ -292,8 +298,6 @@ val = rockchip_canfd_read(rcan, CAN_MODE); val |= WORK_MODE; - if (rcan->mode >= ROCKCHIP_CAN_MODE && rcan->txtorx) - val |= MODE_RXSTX; rockchip_canfd_write(rcan, CAN_MODE, val); netdev_dbg(ndev, "%s MODE=0x%08x\n", __func__, @@ -356,6 +360,12 @@ rockchip_canfd_write(rcan, CAN_DBTP, reg_btp); } + if (bt->bitrate > 200000) + rcan->delay_time_ms = 1; + else if (bt->bitrate > 50000) + rcan->delay_time_ms = 5; + else + rcan->delay_time_ms = 20; netdev_dbg(ndev, "%s NBTP=0x%08x, DBTP=0x%08x, TDCR=0x%08x\n", __func__, rockchip_canfd_read(rcan, CAN_NBTP), @@ -427,7 +437,9 @@ if (rcan->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) val |= MODE_SELF_TEST | MODE_LBACK; - val |= MODE_AUTO_RETX; + /* Listen-only mode */ + if (rcan->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) + val |= MODE_SILENT; rockchip_canfd_write(rcan, CAN_MODE, val); @@ -488,18 +500,26 @@ { struct rockchip_canfd *rcan = container_of(work, struct rockchip_canfd, tx_err_work.work); - u32 mode, err_code, id; + u32 mode, err_code; - id = rockchip_canfd_read(rcan, CAN_TXID); + mode = rockchip_canfd_read(rcan, CAN_MODE); err_code = rockchip_canfd_read(rcan, CAN_ERR_CODE); - if (err_code & 0x1fe0000) { - mode = rockchip_canfd_read(rcan, CAN_MODE); + if ((err_code & NOACK_ERR_FLAG) == NOACK_ERR_FLAG) { + rockchip_canfd_write(rcan, CAN_MODE, + rockchip_canfd_read(rcan, CAN_MODE) | MODE_SPACE_RX); + rockchip_canfd_write(rcan, CAN_CMD, CAN_TX0_REQ); + rockchip_canfd_write(rcan, CAN_MODE, + rockchip_canfd_read(rcan, CAN_MODE) & (~MODE_SPACE_RX)); + schedule_delayed_work(&rcan->tx_err_work, msecs_to_jiffies(rcan->delay_time_ms)); + } else { rockchip_canfd_write(rcan, CAN_MODE, 0); rockchip_canfd_write(rcan, CAN_MODE, mode); + rockchip_canfd_write(rcan, CAN_MODE, + rockchip_canfd_read(rcan, CAN_MODE) | MODE_SPACE_RX); rockchip_canfd_write(rcan, CAN_CMD, CAN_TX0_REQ); - schedule_delayed_work(&rcan->tx_err_work, 1); - } else if (rcan->txtorx && rcan->mode >= ROCKCHIP_CAN_MODE && id & CAN_EFF_FLAG) { - schedule_delayed_work(&rcan->tx_err_work, 1); + rockchip_canfd_write(rcan, CAN_MODE, + rockchip_canfd_read(rcan, CAN_MODE) & (~MODE_SPACE_RX)); + schedule_delayed_work(&rcan->tx_err_work, msecs_to_jiffies(rcan->delay_time_ms)); } } @@ -552,7 +572,14 @@ dlc |= TX_FD_BRS_ENABLE; } - if (!rcan->txtorx && rcan->mode >= ROCKCHIP_CAN_MODE && cf->can_id & CAN_EFF_FLAG) { + if (rcan->txtorx && rcan->mode <= ROCKCHIP_RK3568_CAN_MODE && cf->can_id & CAN_EFF_FLAG) + rockchip_canfd_write(rcan, CAN_MODE, + rockchip_canfd_read(rcan, CAN_MODE) | MODE_RXSTX); + else + rockchip_canfd_write(rcan, CAN_MODE, + rockchip_canfd_read(rcan, CAN_MODE) & (~MODE_RXSTX)); + + if (!rcan->txtorx && rcan->mode <= ROCKCHIP_RK3568_CAN_MODE && cf->can_id & CAN_EFF_FLAG) { /* Two frames are sent consecutively. * Before the first frame is tx finished, * the register of the second frame is configured. @@ -569,10 +596,9 @@ for (i = 0; i < cf->len; i += 4) rockchip_canfd_write(rcan, CAN_TXDAT0 + i, *(u32 *)(cf->data + i)); + can_put_echo_skb(skb, ndev, 0); rockchip_canfd_write(rcan, CAN_CMD, CAN_TX1_REQ); local_irq_restore(flags); - can_put_echo_skb(skb, ndev, 0); - return NETDEV_TX_OK; } @@ -583,13 +609,13 @@ rockchip_canfd_write(rcan, CAN_TXDAT0 + i, *(u32 *)(cf->data + i)); - rockchip_canfd_write(rcan, CAN_CMD, CAN_TX1_REQ); - - if (rcan->txtorx && rcan->mode >= ROCKCHIP_CAN_MODE && cf->can_id & CAN_EFF_FLAG) - schedule_delayed_work(&rcan->tx_err_work, 1); - can_put_echo_skb(skb, ndev, 0); - + rockchip_canfd_write(rcan, CAN_MODE, + rockchip_canfd_read(rcan, CAN_MODE) | MODE_SPACE_RX); + rockchip_canfd_write(rcan, CAN_CMD, cmd); + rockchip_canfd_write(rcan, CAN_MODE, + rockchip_canfd_read(rcan, CAN_MODE) & (~MODE_SPACE_RX)); + schedule_delayed_work(&rcan->tx_err_work, msecs_to_jiffies(rcan->delay_time_ms)); return NETDEV_TX_OK; } @@ -602,15 +628,15 @@ u32 id_rockchip_canfd, dlc; int i = 0; u32 __maybe_unused ts, ret; - u32 data[16] = {0}; + u32 data[16]; dlc = rockchip_canfd_read(rcan, CAN_RXFRD); id_rockchip_canfd = rockchip_canfd_read(rcan, CAN_RXFRD); ts = rockchip_canfd_read(rcan, CAN_RXFRD); - for (i = 0; i < 16; i++) + for (i = 0; i < ARRAY_SIZE(data); i++) data[i] = rockchip_canfd_read(rcan, CAN_RXFRD); - if (rcan->mode >= ROCKCHIP_CAN_MODE) { + if (rcan->mode <= ROCKCHIP_RK3568_CAN_MODE) { /* may be an empty frame */ if (!dlc && !id_rockchip_canfd) return 1; @@ -618,11 +644,10 @@ if (rcan->txtorx) { if (rockchip_canfd_read(rcan, CAN_TX_CHECK_FIC) & FORMAT_MASK) { ret = rockchip_canfd_read(rcan, CAN_TXID) & CAN_SFF_MASK; - if (id_rockchip_canfd == ret) { + if ((id_rockchip_canfd == ret) && !(dlc & FORMAT_MASK)) rockchip_canfd_write(rcan, CAN_TX_CHECK_FIC, ts | CAN_TX0_REQ); - return 1; - } + return 1; } } } @@ -675,6 +700,53 @@ return 1; } +static int rockchip_canfd_get_rx_fifo_cnt(struct net_device *ndev) +{ + struct rockchip_canfd *rcan = netdev_priv(ndev); + int quota = 0; + + if (read_poll_timeout_atomic(rockchip_canfd_read, quota, + (quota & rcan->rx_fifo_mask) >> rcan->rx_fifo_shift, + 0, 500000, false, rcan, CAN_RXFC)) + netdev_dbg(ndev, "Warning: get fifo cnt failed\n"); + + quota = (quota & rcan->rx_fifo_mask) >> rcan->rx_fifo_shift; + + return quota; +} + +/* rockchip_canfd_rx_poll - Poll routine for rx packets (NAPI) + * @napi: napi structure pointer + * @quota: Max number of rx packets to be processed. + * + * This is the poll routine for rx part. + * It will process the packets maximux quota value. + * + * Return: number of packets received + */ +static int rockchip_canfd_rx_poll(struct napi_struct *napi, int quota) +{ + struct net_device *ndev = napi->dev; + struct rockchip_canfd *rcan = netdev_priv(ndev); + int work_done = 0; + + quota = rockchip_canfd_get_rx_fifo_cnt(ndev); + if (quota) { + while (work_done < quota) + work_done += rockchip_canfd_rx(ndev); + } + + if (work_done) + can_led_event(ndev, CAN_LED_EVENT_RX); + + if (work_done < 6) { + napi_complete_done(napi, work_done); + rockchip_canfd_write(rcan, CAN_INT_MASK, 0); + } + + return work_done; +} + static int rockchip_canfd_err(struct net_device *ndev, u32 isr) { struct rockchip_canfd *rcan = netdev_priv(ndev); @@ -724,8 +796,14 @@ } if (rcan->can.state >= CAN_STATE_BUS_OFF || - ((sta_reg & 0x20) == 0x20)) - can_bus_off(ndev); + ((sta_reg & CAN_BUSOFF_FLAG) == CAN_BUSOFF_FLAG)) { + cancel_delayed_work(&rcan->tx_err_work); + netif_stop_queue(ndev); + rockchip_canfd_stop(ndev); + can_free_echo_skb(ndev, 0); + rockchip_canfd_start(ndev); + netif_start_queue(ndev); + } stats->rx_packets++; stats->rx_bytes += cf->can_dlc; @@ -740,13 +818,14 @@ struct rockchip_canfd *rcan = netdev_priv(ndev); struct net_device_stats *stats = &ndev->stats; u32 err_int = ERR_WARN_INT | RX_BUF_OV_INT | PASSIVE_ERR_INT | - TX_LOSTARB_INT | BUS_ERR_INT | BUS_OFF_INT; + BUS_ERR_INT | BUS_OFF_INT; u32 isr; u32 dlc = 0; u32 quota, work_done = 0; isr = rockchip_canfd_read(rcan, CAN_INT); if (isr & TX_FINISH_INT) { + cancel_delayed_work(&rcan->tx_err_work); dlc = rockchip_canfd_read(rcan, CAN_TXFIC); /* transmission complete interrupt */ if (dlc & FDF_MASK) @@ -754,12 +833,9 @@ else stats->tx_bytes += (dlc & DLC_MASK); stats->tx_packets++; - if (rcan->txtorx && rcan->mode >= ROCKCHIP_CAN_MODE && dlc & FORMAT_MASK) { - cancel_delayed_work(&rcan->tx_err_work); + if (rcan->txtorx && rcan->mode <= ROCKCHIP_RK3568_CAN_MODE && dlc & FORMAT_MASK) { rockchip_canfd_write(rcan, CAN_TX_CHECK_FIC, FORMAT_MASK); - quota = (rockchip_canfd_read(rcan, CAN_RXFC) & - rcan->rx_fifo_mask) >> - rcan->rx_fifo_shift; + quota = rockchip_canfd_get_rx_fifo_cnt(ndev); if (quota) { while (work_done < quota) work_done += rockchip_canfd_rx(ndev); @@ -768,6 +844,10 @@ rockchip_canfd_write(rcan, CAN_CMD, CAN_TX1_REQ); rockchip_canfd_write(rcan, CAN_TX_CHECK_FIC, 0); } + if (read_poll_timeout_atomic(rockchip_canfd_read, quota, + !(quota & 0x3), + 0, 5000000, false, rcan, CAN_CMD)) + netdev_err(ndev, "Warning: wait tx req timeout!\n"); rockchip_canfd_write(rcan, CAN_CMD, 0); can_get_echo_skb(ndev, 0); netif_wake_queue(ndev); @@ -775,11 +855,18 @@ } if (isr & RX_FINISH_INT) { - quota = (rockchip_canfd_read(rcan, CAN_RXFC) & rcan->rx_fifo_mask) >> - rcan->rx_fifo_shift; - if (quota) { - while (work_done < quota) - work_done += rockchip_canfd_rx(ndev); + if (rcan->mode == ROCKCHIP_RK3568_CAN_MODE_V2) { + rockchip_canfd_write(rcan, CAN_INT_MASK, 0x1); + napi_schedule(&rcan->napi); + } else { + work_done = 0; + quota = (rockchip_canfd_read(rcan, CAN_RXFC) & + rcan->rx_fifo_mask) >> + rcan->rx_fifo_shift; + if (quota) { + while (work_done < quota) + work_done += rockchip_canfd_rx(ndev); + } } } @@ -817,6 +904,8 @@ } can_led_event(ndev, CAN_LED_EVENT_OPEN); + if (rcan->mode == ROCKCHIP_RK3568_CAN_MODE_V2) + napi_enable(&rcan->napi); netif_start_queue(ndev); netdev_dbg(ndev, "%s\n", __func__); @@ -834,6 +923,8 @@ struct rockchip_canfd *rcan = netdev_priv(ndev); netif_stop_queue(ndev); + if (rcan->mode == ROCKCHIP_RK3568_CAN_MODE_V2) + napi_disable(&rcan->napi); rockchip_canfd_stop(ndev); close_candev(ndev); can_led_event(ndev, CAN_LED_EVENT_STOP); @@ -1011,6 +1102,9 @@ rcan->mode = (unsigned long)of_device_get_match_data(&pdev->dev); + if ((cpu_is_rk3566() || cpu_is_rk3568()) && (rockchip_get_cpu_version() == 3)) + rcan->mode = ROCKCHIP_RK3568_CAN_MODE_V2; + rcan->base = addr; rcan->can.clock.freq = clk_get_rate(rcan->clks[0].clk); rcan->dev = &pdev->dev; @@ -1032,6 +1126,7 @@ break; case ROCKCHIP_CAN_MODE: case ROCKCHIP_RK3568_CAN_MODE: + case ROCKCHIP_RK3568_CAN_MODE_V2: rcan->can.bittiming_const = &rockchip_canfd_bittiming_const; rcan->can.do_set_mode = rockchip_canfd_set_mode; rcan->can.do_get_berr_counter = rockchip_canfd_get_berr_counter; @@ -1056,10 +1151,17 @@ rcan->tx_invalid, 4)) rcan->txtorx = 1; + if (rcan->mode == ROCKCHIP_RK3568_CAN_MODE_V2) { + rcan->txtorx = 0; + netif_napi_add(ndev, &rcan->napi, rockchip_canfd_rx_poll, 6); + } + ndev->netdev_ops = &rockchip_canfd_netdev_ops; ndev->irq = irq; ndev->flags |= IFF_ECHO; rcan->can.restart_ms = 1; + + irq_set_affinity_hint(irq, get_cpu_mask(num_online_cpus() - 1)); INIT_DELAYED_WORK(&rcan->tx_err_work, rockchip_canfd_tx_err_delay_work); @@ -1097,9 +1199,12 @@ static int rockchip_canfd_remove(struct platform_device *pdev) { struct net_device *ndev = platform_get_drvdata(pdev); + struct rockchip_canfd *rcan = netdev_priv(ndev); unregister_netdev(ndev); pm_runtime_disable(&pdev->dev); + if (rcan->mode == ROCKCHIP_RK3568_CAN_MODE_V2) + netif_napi_del(&rcan->napi); free_candev(ndev); return 0; -- Gitblit v1.6.2