From 102a0743326a03cd1a1202ceda21e175b7d3575c Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Tue, 20 Feb 2024 01:20:52 +0000 Subject: [PATCH] add new system file --- kernel/drivers/spi/spi-tegra114.c | 356 ++++++++++++++++++++++++++++++++++++++++++++++++---------- 1 files changed, 292 insertions(+), 64 deletions(-) diff --git a/kernel/drivers/spi/spi-tegra114.c b/kernel/drivers/spi/spi-tegra114.c index c510b53..ed42665 100644 --- a/kernel/drivers/spi/spi-tegra114.c +++ b/kernel/drivers/spi/spi-tegra114.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * SPI driver for NVIDIA's Tegra114 SPI Controller. * * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/clk.h> @@ -95,8 +84,10 @@ (reg = (((val) & 0x1) << ((cs) * 8 + 5)) | \ ((reg) & ~(1 << ((cs) * 8 + 5)))) #define SPI_SET_CYCLES_BETWEEN_PACKETS(reg, cs, val) \ - (reg = (((val) & 0xF) << ((cs) * 8)) | \ - ((reg) & ~(0xF << ((cs) * 8)))) + (reg = (((val) & 0x1F) << ((cs) * 8)) | \ + ((reg) & ~(0x1F << ((cs) * 8)))) +#define MAX_SETUP_HOLD_CYCLES 16 +#define MAX_INACTIVE_CYCLES 32 #define SPI_TRANS_STATUS 0x010 #define SPI_BLK_CNT(val) (((val) >> 0) & 0xFFFF) @@ -149,6 +140,8 @@ #define SPI_TX_FIFO 0x108 #define SPI_RX_FIFO 0x188 +#define SPI_INTR_MASK 0x18c +#define SPI_INTR_ALL_MASK (0x1fUL << 25) #define MAX_CHIP_SELECT 4 #define SPI_FIFO_DEPTH 64 #define DATA_DIR_TX (1 << 0) @@ -160,6 +153,15 @@ #define RX_FIFO_FULL_COUNT_ZERO SPI_RX_FIFO_FULL_COUNT(0) #define MAX_HOLD_CYCLES 16 #define SPI_DEFAULT_SPEED 25000000 + +struct tegra_spi_soc_data { + bool has_intr_mask_reg; +}; + +struct tegra_spi_client_data { + int tx_clk_tap_delay; + int rx_clk_tap_delay; +}; struct tegra_spi_data { struct device *dev; @@ -187,6 +189,7 @@ unsigned dma_buf_size; unsigned max_buf_size; bool is_curr_dma_xfer; + bool use_hw_based_cs; struct completion rx_dma_complete; struct completion tx_dma_complete; @@ -199,6 +202,10 @@ u32 command1_reg; u32 dma_control_reg; u32 def_command1_reg; + u32 def_command2_reg; + u32 spi_cs_timing1; + u32 spi_cs_timing2; + u8 last_used_cs; struct completion xfer_completion; struct spi_transfer *curr_xfer; @@ -211,6 +218,7 @@ u32 *tx_dma_buf; dma_addr_t tx_dma_phys; struct dma_async_tx_descriptor *tx_dma_desc; + const struct tegra_spi_soc_data *soc_data; }; static int tegra_spi_runtime_suspend(struct device *dev); @@ -259,11 +267,12 @@ tspi->bytes_per_word = DIV_ROUND_UP(bits_per_word, 8); - if (bits_per_word == 8 || bits_per_word == 16) { - tspi->is_packed = 1; + if ((bits_per_word == 8 || bits_per_word == 16 || + bits_per_word == 32) && t->len > 3) { + tspi->is_packed = true; tspi->words_per_32bit = 32/bits_per_word; } else { - tspi->is_packed = 0; + tspi->is_packed = false; tspi->words_per_32bit = 1; } @@ -553,11 +562,13 @@ dma_burst = 8; } - if (tspi->cur_direction & DATA_DIR_TX) - val |= SPI_IE_TX; + if (!tspi->soc_data->has_intr_mask_reg) { + if (tspi->cur_direction & DATA_DIR_TX) + val |= SPI_IE_TX; - if (tspi->cur_direction & DATA_DIR_RX) - val |= SPI_IE_RX; + if (tspi->cur_direction & DATA_DIR_RX) + val |= SPI_IE_RX; + } tegra_spi_writel(tspi, val, SPI_DMA_CTL); tspi->dma_control_reg = val; @@ -641,8 +652,9 @@ tspi->is_curr_dma_xfer = false; - val |= SPI_DMA_EN; - tegra_spi_writel(tspi, val, SPI_DMA_CTL); + val = tspi->command1_reg; + val |= SPI_PIO; + tegra_spi_writel(tspi, val, SPI_COMMAND1); return 0; } @@ -652,17 +664,11 @@ struct dma_chan *dma_chan; u32 *dma_buf; dma_addr_t dma_phys; - int ret; - dma_chan = dma_request_slave_channel_reason(tspi->dev, - dma_to_memory ? "rx" : "tx"); - if (IS_ERR(dma_chan)) { - ret = PTR_ERR(dma_chan); - if (ret != -EPROBE_DEFER) - dev_err(tspi->dev, - "Dma channel is not available: %d\n", ret); - return ret; - } + dma_chan = dma_request_chan(tspi->dev, dma_to_memory ? "rx" : "tx"); + if (IS_ERR(dma_chan)) + return dev_err_probe(tspi->dev, PTR_ERR(dma_chan), + "Dma channel is not available\n"); dma_buf = dma_alloc_coherent(tspi->dev, tspi->dma_buf_size, &dma_phys, GFP_KERNEL); @@ -711,14 +717,73 @@ dma_release_channel(dma_chan); } -static u32 tegra_spi_setup_transfer_one(struct spi_device *spi, - struct spi_transfer *t, bool is_first_of_msg) +static int tegra_spi_set_hw_cs_timing(struct spi_device *spi, + struct spi_delay *setup, + struct spi_delay *hold, + struct spi_delay *inactive) { struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master); + u8 setup_dly, hold_dly, inactive_dly; + u32 setup_hold; + u32 spi_cs_timing; + u32 inactive_cycles; + u8 cs_state; + + if ((setup && setup->unit != SPI_DELAY_UNIT_SCK) || + (hold && hold->unit != SPI_DELAY_UNIT_SCK) || + (inactive && inactive->unit != SPI_DELAY_UNIT_SCK)) { + dev_err(&spi->dev, + "Invalid delay unit %d, should be SPI_DELAY_UNIT_SCK\n", + SPI_DELAY_UNIT_SCK); + return -EINVAL; + } + + setup_dly = setup ? setup->value : 0; + hold_dly = hold ? hold->value : 0; + inactive_dly = inactive ? inactive->value : 0; + + setup_dly = min_t(u8, setup_dly, MAX_SETUP_HOLD_CYCLES); + hold_dly = min_t(u8, hold_dly, MAX_SETUP_HOLD_CYCLES); + if (setup_dly && hold_dly) { + setup_hold = SPI_SETUP_HOLD(setup_dly - 1, hold_dly - 1); + spi_cs_timing = SPI_CS_SETUP_HOLD(tspi->spi_cs_timing1, + spi->chip_select, + setup_hold); + if (tspi->spi_cs_timing1 != spi_cs_timing) { + tspi->spi_cs_timing1 = spi_cs_timing; + tegra_spi_writel(tspi, spi_cs_timing, SPI_CS_TIMING1); + } + } + + inactive_cycles = min_t(u8, inactive_dly, MAX_INACTIVE_CYCLES); + if (inactive_cycles) + inactive_cycles--; + cs_state = inactive_cycles ? 0 : 1; + spi_cs_timing = tspi->spi_cs_timing2; + SPI_SET_CS_ACTIVE_BETWEEN_PACKETS(spi_cs_timing, spi->chip_select, + cs_state); + SPI_SET_CYCLES_BETWEEN_PACKETS(spi_cs_timing, spi->chip_select, + inactive_cycles); + if (tspi->spi_cs_timing2 != spi_cs_timing) { + tspi->spi_cs_timing2 = spi_cs_timing; + tegra_spi_writel(tspi, spi_cs_timing, SPI_CS_TIMING2); + } + + return 0; +} + +static u32 tegra_spi_setup_transfer_one(struct spi_device *spi, + struct spi_transfer *t, + bool is_first_of_msg, + bool is_single_xfer) +{ + struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master); + struct tegra_spi_client_data *cdata = spi->controller_data; u32 speed = t->speed_hz; u8 bits_per_word = t->bits_per_word; - u32 command1; + u32 command1, command2; int req_mode; + u32 tx_tap = 0, rx_tap = 0; if (speed != tspi->cur_speed) { clk_set_rate(tspi->clk, speed); @@ -748,6 +813,16 @@ else if (req_mode == SPI_MODE_3) command1 |= SPI_CONTROL_MODE_3; + if (spi->mode & SPI_LSB_FIRST) + command1 |= SPI_LSBIT_FE; + else + command1 &= ~SPI_LSBIT_FE; + + if (spi->mode & SPI_3WIRE) + command1 |= SPI_BIDIROE; + else + command1 &= ~SPI_BIDIROE; + if (tspi->cs_control) { if (tspi->cs_control != spi) tegra_spi_writel(tspi, command1, SPI_COMMAND1); @@ -755,13 +830,34 @@ } else tegra_spi_writel(tspi, command1, SPI_COMMAND1); - command1 |= SPI_CS_SW_HW; - if (spi->mode & SPI_CS_HIGH) - command1 |= SPI_CS_SW_VAL; - else - command1 &= ~SPI_CS_SW_VAL; + /* GPIO based chip select control */ + if (spi->cs_gpiod) + gpiod_set_value(spi->cs_gpiod, 1); - tegra_spi_writel(tspi, 0, SPI_COMMAND2); + if (is_single_xfer && !(t->cs_change)) { + tspi->use_hw_based_cs = true; + command1 &= ~(SPI_CS_SW_HW | SPI_CS_SW_VAL); + } else { + tspi->use_hw_based_cs = false; + command1 |= SPI_CS_SW_HW; + if (spi->mode & SPI_CS_HIGH) + command1 |= SPI_CS_SW_VAL; + else + command1 &= ~SPI_CS_SW_VAL; + } + + if (tspi->last_used_cs != spi->chip_select) { + if (cdata && cdata->tx_clk_tap_delay) + tx_tap = cdata->tx_clk_tap_delay; + if (cdata && cdata->rx_clk_tap_delay) + rx_tap = cdata->rx_clk_tap_delay; + command2 = SPI_TX_TAP_DELAY(tx_tap) | + SPI_RX_TAP_DELAY(rx_tap); + if (command2 != tspi->def_command2_reg) + tegra_spi_writel(tspi, command2, SPI_COMMAND2); + tspi->last_used_cs = spi->chip_select; + } + } else { command1 = tspi->command1_reg; command1 &= ~SPI_BIT_LENGTH(~0); @@ -779,6 +875,11 @@ int ret; total_fifo_words = tegra_spi_calculate_curr_xfer_param(spi, tspi, t); + + if (t->rx_nbits == SPI_NBITS_DUAL || t->tx_nbits == SPI_NBITS_DUAL) + command1 |= SPI_BOTH_EN_BIT; + else + command1 &= ~SPI_BOTH_EN_BIT; if (tspi->is_packed) command1 |= SPI_PACKED; @@ -812,9 +913,42 @@ return ret; } +static struct tegra_spi_client_data + *tegra_spi_parse_cdata_dt(struct spi_device *spi) +{ + struct tegra_spi_client_data *cdata; + struct device_node *slave_np; + + slave_np = spi->dev.of_node; + if (!slave_np) { + dev_dbg(&spi->dev, "device node not found\n"); + return NULL; + } + + cdata = kzalloc(sizeof(*cdata), GFP_KERNEL); + if (!cdata) + return NULL; + + of_property_read_u32(slave_np, "nvidia,tx-clk-tap-delay", + &cdata->tx_clk_tap_delay); + of_property_read_u32(slave_np, "nvidia,rx-clk-tap-delay", + &cdata->rx_clk_tap_delay); + return cdata; +} + +static void tegra_spi_cleanup(struct spi_device *spi) +{ + struct tegra_spi_client_data *cdata = spi->controller_data; + + spi->controller_data = NULL; + if (spi->dev.of_node) + kfree(cdata); +} + static int tegra_spi_setup(struct spi_device *spi) { struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master); + struct tegra_spi_client_data *cdata = spi->controller_data; u32 val; unsigned long flags; int ret; @@ -825,14 +959,31 @@ spi->mode & SPI_CPHA ? "" : "~", spi->max_speed_hz); + if (!cdata) { + cdata = tegra_spi_parse_cdata_dt(spi); + spi->controller_data = cdata; + } + ret = pm_runtime_get_sync(tspi->dev); if (ret < 0) { pm_runtime_put_noidle(tspi->dev); dev_err(tspi->dev, "pm runtime failed, e = %d\n", ret); + if (cdata) + tegra_spi_cleanup(spi); return ret; } + if (tspi->soc_data->has_intr_mask_reg) { + val = tegra_spi_readl(tspi, SPI_INTR_MASK); + val &= ~SPI_INTR_ALL_MASK; + tegra_spi_writel(tspi, val, SPI_INTR_MASK); + } + spin_lock_irqsave(&tspi->lock, flags); + /* GPIO based chip select control */ + if (spi->cs_gpiod) + gpiod_set_value(spi->cs_gpiod, 0); + val = tspi->def_command1_reg; if (spi->mode & SPI_CS_HIGH) val &= ~SPI_CS_POL_INACTIVE(spi->chip_select); @@ -846,15 +997,38 @@ return 0; } -static void tegra_spi_transfer_delay(int delay) +static void tegra_spi_transfer_end(struct spi_device *spi) { - if (!delay) - return; + struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master); + int cs_val = (spi->mode & SPI_CS_HIGH) ? 0 : 1; - if (delay >= 1000) - mdelay(delay / 1000); + /* GPIO based chip select control */ + if (spi->cs_gpiod) + gpiod_set_value(spi->cs_gpiod, 0); - udelay(delay % 1000); + if (!tspi->use_hw_based_cs) { + if (cs_val) + tspi->command1_reg |= SPI_CS_SW_VAL; + else + tspi->command1_reg &= ~SPI_CS_SW_VAL; + tegra_spi_writel(tspi, tspi->command1_reg, SPI_COMMAND1); + } + + tegra_spi_writel(tspi, tspi->def_command1_reg, SPI_COMMAND1); +} + +static void tegra_spi_dump_regs(struct tegra_spi_data *tspi) +{ + dev_dbg(tspi->dev, "============ SPI REGISTER DUMP ============\n"); + dev_dbg(tspi->dev, "Command1: 0x%08x | Command2: 0x%08x\n", + tegra_spi_readl(tspi, SPI_COMMAND1), + tegra_spi_readl(tspi, SPI_COMMAND2)); + dev_dbg(tspi->dev, "DMA_CTL: 0x%08x | DMA_BLK: 0x%08x\n", + tegra_spi_readl(tspi, SPI_DMA_CTL), + tegra_spi_readl(tspi, SPI_DMA_BLK)); + dev_dbg(tspi->dev, "TRANS_STAT: 0x%08x | FIFO_STATUS: 0x%08x\n", + tegra_spi_readl(tspi, SPI_TRANS_STATUS), + tegra_spi_readl(tspi, SPI_FIFO_STATUS)); } static int tegra_spi_transfer_one_message(struct spi_master *master, @@ -866,16 +1040,19 @@ struct spi_device *spi = msg->spi; int ret; bool skip = false; + int single_xfer; msg->status = 0; msg->actual_length = 0; + single_xfer = list_is_singular(&msg->transfers); list_for_each_entry(xfer, &msg->transfers, transfer_list) { u32 cmd1; reinit_completion(&tspi->xfer_completion); - cmd1 = tegra_spi_setup_transfer_one(spi, xfer, is_first_msg); + cmd1 = tegra_spi_setup_transfer_one(spi, xfer, is_first_msg, + single_xfer); if (!xfer->len) { ret = 0; @@ -903,39 +1080,39 @@ (tspi->cur_direction & DATA_DIR_RX)) dmaengine_terminate_all(tspi->rx_dma_chan); ret = -EIO; + tegra_spi_dump_regs(tspi); tegra_spi_flush_fifos(tspi); reset_control_assert(tspi->rst); udelay(2); reset_control_deassert(tspi->rst); + tspi->last_used_cs = master->num_chipselect + 1; goto complete_xfer; } if (tspi->tx_status || tspi->rx_status) { dev_err(tspi->dev, "Error in Transfer\n"); ret = -EIO; + tegra_spi_dump_regs(tspi); goto complete_xfer; } msg->actual_length += xfer->len; complete_xfer: if (ret < 0 || skip) { - tegra_spi_writel(tspi, tspi->def_command1_reg, - SPI_COMMAND1); - tegra_spi_transfer_delay(xfer->delay_usecs); + tegra_spi_transfer_end(spi); + spi_transfer_delay_exec(xfer); goto exit; } else if (list_is_last(&xfer->transfer_list, &msg->transfers)) { if (xfer->cs_change) tspi->cs_control = spi; else { - tegra_spi_writel(tspi, tspi->def_command1_reg, - SPI_COMMAND1); - tegra_spi_transfer_delay(xfer->delay_usecs); + tegra_spi_transfer_end(spi); + spi_transfer_delay_exec(xfer); } } else if (xfer->cs_change) { - tegra_spi_writel(tspi, tspi->def_command1_reg, - SPI_COMMAND1); - tegra_spi_transfer_delay(xfer->delay_usecs); + tegra_spi_transfer_end(spi); + spi_transfer_delay_exec(xfer); } } @@ -957,12 +1134,14 @@ tspi->status_reg); dev_err(tspi->dev, "CpuXfer 0x%08x:0x%08x\n", tspi->command1_reg, tspi->dma_control_reg); + tegra_spi_dump_regs(tspi); tegra_spi_flush_fifos(tspi); + complete(&tspi->xfer_completion); + spin_unlock_irqrestore(&tspi->lock, flags); reset_control_assert(tspi->rst); udelay(2); reset_control_deassert(tspi->rst); - complete(&tspi->xfer_completion); - goto exit; + return IRQ_HANDLED; } if (tspi->cur_direction & DATA_DIR_RX) @@ -1030,12 +1209,13 @@ tspi->status_reg); dev_err(tspi->dev, "DmaXfer 0x%08x:0x%08x\n", tspi->command1_reg, tspi->dma_control_reg); + tegra_spi_dump_regs(tspi); tegra_spi_flush_fifos(tspi); + complete(&tspi->xfer_completion); + spin_unlock_irqrestore(&tspi->lock, flags); reset_control_assert(tspi->rst); udelay(2); reset_control_deassert(tspi->rst); - complete(&tspi->xfer_completion); - spin_unlock_irqrestore(&tspi->lock, flags); return IRQ_HANDLED; } @@ -1091,8 +1271,29 @@ return IRQ_WAKE_THREAD; } +static struct tegra_spi_soc_data tegra114_spi_soc_data = { + .has_intr_mask_reg = false, +}; + +static struct tegra_spi_soc_data tegra124_spi_soc_data = { + .has_intr_mask_reg = false, +}; + +static struct tegra_spi_soc_data tegra210_spi_soc_data = { + .has_intr_mask_reg = true, +}; + static const struct of_device_id tegra_spi_of_match[] = { - { .compatible = "nvidia,tegra114-spi", }, + { + .compatible = "nvidia,tegra114-spi", + .data = &tegra114_spi_soc_data, + }, { + .compatible = "nvidia,tegra124-spi", + .data = &tegra124_spi_soc_data, + }, { + .compatible = "nvidia,tegra210-spi", + .data = &tegra210_spi_soc_data, + }, {} }; MODULE_DEVICE_TABLE(of, tegra_spi_of_match); @@ -1103,6 +1304,7 @@ struct tegra_spi_data *tspi; struct resource *r; int ret, spi_irq; + int bus_num; master = spi_alloc_master(&pdev->dev, sizeof(*tspi)); if (!master) { @@ -1117,15 +1319,30 @@ master->max_speed_hz = 25000000; /* 25MHz */ /* the spi->mode bits understood by this driver: */ - master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; + master->use_gpio_descriptors = true; + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST | + SPI_TX_DUAL | SPI_RX_DUAL | SPI_3WIRE; + master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); master->setup = tegra_spi_setup; + master->cleanup = tegra_spi_cleanup; master->transfer_one_message = tegra_spi_transfer_one_message; + master->set_cs_timing = tegra_spi_set_hw_cs_timing; master->num_chipselect = MAX_CHIP_SELECT; master->auto_runtime_pm = true; + bus_num = of_alias_get_id(pdev->dev.of_node, "spi"); + if (bus_num >= 0) + master->bus_num = bus_num; tspi->master = master; tspi->dev = &pdev->dev; spin_lock_init(&tspi->lock); + + tspi->soc_data = of_device_get_match_data(&pdev->dev); + if (!tspi->soc_data) { + dev_err(&pdev->dev, "unsupported tegra\n"); + ret = -ENODEV; + goto exit_free_master; + } r = platform_get_resource(pdev, IORESOURCE_MEM, 0); tspi->base = devm_ioremap_resource(&pdev->dev, r); @@ -1136,6 +1353,10 @@ tspi->phys = r->start; spi_irq = platform_get_irq(pdev, 0); + if (spi_irq < 0) { + ret = spi_irq; + goto exit_free_master; + } tspi->irq = spi_irq; tspi->clk = devm_clk_get(&pdev->dev, "spi"); @@ -1177,6 +1398,7 @@ ret = pm_runtime_get_sync(&pdev->dev); if (ret < 0) { dev_err(&pdev->dev, "pm runtime get failed, e = %d\n", ret); + pm_runtime_put_noidle(&pdev->dev); goto exit_pm_disable; } @@ -1185,6 +1407,10 @@ reset_control_deassert(tspi->rst); tspi->def_command1_reg = SPI_M_S; tegra_spi_writel(tspi, tspi->def_command1_reg, SPI_COMMAND1); + tspi->spi_cs_timing1 = tegra_spi_readl(tspi, SPI_CS_TIMING1); + tspi->spi_cs_timing2 = tegra_spi_readl(tspi, SPI_CS_TIMING2); + tspi->def_command2_reg = tegra_spi_readl(tspi, SPI_COMMAND2); + tspi->last_used_cs = master->num_chipselect + 1; pm_runtime_put(&pdev->dev); ret = request_threaded_irq(tspi->irq, tegra_spi_isr, tegra_spi_isr_thread, IRQF_ONESHOT, @@ -1258,6 +1484,8 @@ return ret; } tegra_spi_writel(tspi, tspi->command1_reg, SPI_COMMAND1); + tegra_spi_writel(tspi, tspi->def_command2_reg, SPI_COMMAND2); + tspi->last_used_cs = master->num_chipselect + 1; pm_runtime_put(dev); return spi_master_resume(master); -- Gitblit v1.6.2