Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions drivers/spi/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -776,7 +776,7 @@ config SPI_PCI1XXXX

config SPI_PHYTIUM
tristate
depends on ARCH_PHYTIUM || COMPILE_TEST
depends on ARCH_PHYTIUM

config SPI_PHYTIUM_PLAT
tristate "Phytium SPI controller platform support"
Expand Down Expand Up @@ -816,13 +816,14 @@ config SPI_PHYTIUM_QSPI

config SPI_PHYTIUM_V2
tristate "spi phytium v2"
depends on ARCH_PHYTIUM || COMPILE_TEST
depends on ARCH_PHYTIUM
help
This config is similar to the "SPI_PHYTIUM" config.

config SPI_PHYTIUM_PLAT_V2
tristate "Phytium SPI-v2 controller platform support"
select SPI_PHYTIUM_V2
depends on ARCH_PHYTIUM
help
This config is similar to the "SPI_PHYTIUM_PLAT" config.

Expand Down
84 changes: 76 additions & 8 deletions drivers/spi/spi-phytium-common.c
Original file line number Diff line number Diff line change
Expand Up @@ -110,11 +110,15 @@ int spi_phytium_print_status(struct phytium_spi *fts, u8 status0,

int spi_phytium_check_result(struct phytium_spi *fts)
{
unsigned long long ms = 300000;
unsigned long long ms = 20000;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): The new default timeout is 20 seconds, but the long-timeout condition is checked through fts->flash_erase == 2; the chip-erase path calls spi_phytium_flash_erase() while flash_erase is still zero and sets it to 2 only after that call returns. A chip erase taking more than 20 seconds therefore times out before the intended 200-second timeout is selected.

Triggers: When a chip erase takes longer than 20 seconds.

Suggested fix: Mark the operation as a long-running chip erase before calling spi_phytium_flash_erase(), or pass the operation-specific timeout explicitly.

struct msg *msg = (struct msg *)fts->tx_shmem_addr;

if (fts->flash_erase == 2)
ms = 200000;

reinit_completion(&fts->cmd_completion);
ms = wait_for_completion_timeout(&fts->cmd_completion, msecs_to_jiffies(ms));
phytium_write_regfile(fts, SPI_REGFILE_AP2RV_INTR_STATE, 0x10);
ms = wait_for_completion_interruptible_timeout(&fts->cmd_completion, msecs_to_jiffies(ms));

if (ms == 0) {
dev_err(&fts->master->dev, "SPI controller timed out\n");
Expand All @@ -129,7 +133,6 @@ int spi_phytium_set(struct phytium_spi *fts)
int ret;

spi_phytium_show_msg(fts->msg);
phytium_write_regfile(fts, SPI_REGFILE_AP2RV_INTR_STATE, 0x10);
ret = spi_phytium_check_result(fts);

return ret;
Expand All @@ -142,7 +145,6 @@ void spi_phytium_default(struct phytium_spi *fts)
fts->msg->cmd_id = PHYTSPI_MSG_CMD_DEFAULT;

spi_phytium_show_msg(fts->msg);
phytium_write_regfile(fts, SPI_REGFILE_AP2RV_INTR_STATE, 0x10);
spi_phytium_check_result(fts);
}
EXPORT_SYMBOL_GPL(spi_phytium_default);
Expand All @@ -160,7 +162,6 @@ void spi_phytium_set_cmd8(struct phytium_spi *fts, u16 sub_cmd,
spi_phytium_set_subid(fts, sub_cmd);
fts->msg->data[0] = data;
spi_phytium_show_msg(fts->msg);
phytium_write_regfile(fts, SPI_REGFILE_AP2RV_INTR_STATE, 0x10);
spi_phytium_check_result(fts);
}
EXPORT_SYMBOL_GPL(spi_phytium_set_cmd8);
Expand All @@ -174,7 +175,6 @@ void spi_phytium_set_cmd16(struct phytium_spi *fts, u16 sub_cmd,
spi_phytium_set_subid(fts, sub_cmd);
*cp_data = data;
spi_phytium_show_msg(fts->msg);
phytium_write_regfile(fts, SPI_REGFILE_AP2RV_INTR_STATE, 0x10);
spi_phytium_check_result(fts);
}
EXPORT_SYMBOL_GPL(spi_phytium_set_cmd16);
Expand All @@ -188,7 +188,6 @@ void spi_phytium_set_cmd32(struct phytium_spi *fts, u16 sub_cmd,
spi_phytium_set_subid(fts, sub_cmd);
*cp_data = data;
spi_phytium_show_msg(fts->msg);
phytium_write_regfile(fts, SPI_REGFILE_AP2RV_INTR_STATE, 0x10);
spi_phytium_check_result(fts);
}
EXPORT_SYMBOL_GPL(spi_phytium_set_cmd32);
Expand Down Expand Up @@ -332,7 +331,7 @@ int spi_phytium_write(struct phytium_spi *fts, u8 cs, u8 dfs, u8 mode,
u64 tx_addr;

if (spi_write_flag == 1) {
spi_phytium_set(fts);
ret = spi_phytium_set(fts);
if (ret) {
dev_err(&fts->master->dev, "AP <-> RV interaction failed\n");
return ret;
Expand Down Expand Up @@ -452,6 +451,75 @@ int spi_phytium_read(struct phytium_spi *fts, u8 cs, u8 dfs, u8 mode,
}
EXPORT_SYMBOL_GPL(spi_phytium_read);

int spi_phytium_xfer(struct phytium_spi *fts, u8 cs, u8 dfs, u8 mode,
u8 tmode, u8 flags)
{
int ret;
u32 len;
u64 smem_tx, smem_rx;
u8 first = 1;
u64 tx_addr, rx_addr;

do {
if (fts->dma_get_ddrdata)
len = min_t(u32, (u32)(fts->rx_end - fts->rx),
(u32)(fts->rx_end - fts->rx));
else
len = min_t(u32, (u32)(fts->rx_end - fts->rx), 128);

fts->msg->cmd_id = PHYTSPI_MSG_CMD_DATA;

smem_tx = (u64)fts->msg + sizeof(struct msg);
smem_rx = (u64)fts->msg + sizeof(struct msg) + 128;

if (len > 16 && fts->dma_get_ddrdata) {
fts->msg->cmd_subid = PHYTSPI_MSG_CMD_DATA_DMA_XFER;
tx_addr = __virt_to_phys((u64)fts->tx);
if (!tx_addr) {
dev_err(&fts->master->dev, "tx address translation failed\n");
return -1;
}
rx_addr = __virt_to_phys((u64)fts->rx);
if (!rx_addr) {
dev_err(&fts->master->dev, "rx address translation failed\n");
return -1;
}

*(u64 *)&fts->msg->data[0] = tx_addr;
*(u64 *)&fts->msg->data[8] = rx_addr;
} else {
fts->msg->cmd_subid = PHYTSPI_MSG_CMD_DATA_XFER;
memcpy_byte((void *)smem_tx, fts->tx, len);
*(u64 *)&fts->msg->data[0] = sizeof(struct msg);
*(u64 *)&fts->msg->data[8] = sizeof(struct msg) + 128;
}

*(u32 *)&fts->msg->data[16] = len;
fts->msg->data[20] = cs;
fts->msg->data[21] = dfs;
fts->msg->data[22] = mode;
fts->msg->data[23] = tmode;
if (first == 1)
fts->msg->data[24] = 1;
else
fts->msg->data[24] = flags;
fts->msg->data[24] = first;
ret = spi_phytium_set(fts);
if (ret) {
dev_err(&fts->master->dev, "AP <-> RV interaction failed\n");
return ret;
}
if (len <= 16 || !fts->dma_get_ddrdata)
memcpy_byte(fts->rx, (void *)smem_rx, len);

fts->rx += len;
first = 0;
} while (fts->rx_end > fts->rx);

return ret;
}
EXPORT_SYMBOL_GPL(spi_phytium_xfer);

MODULE_AUTHOR("Peng Min <pengmin1540@phytium.com.cn>");
MODULE_DESCRIPTION("Phytium SPI adapter core");
MODULE_LICENSE("GPL");
13 changes: 11 additions & 2 deletions drivers/spi/spi-phytium-dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
#include <linux/types.h>
#include <linux/delay.h>
#include "spi-phytium.h"
#include <linux/acpi.h>
#include <linux/acpi_dma.h>

#define RX_BUSY 0
#define RX_BURST_LEVEL 16
Expand Down Expand Up @@ -64,11 +66,18 @@ static void phytium_spi_dma_maxburst_init(struct phytium_spi *fts)
static int phytium_spi_dma_init(struct device *dev,
struct phytium_spi *fts)
{
fts->rxchan = dma_request_chan(dev, "rx");
/* Support ACPI (FixedDMA) and DT (dmas/dma-names) */
if (has_acpi_companion(dev))
fts->rxchan = acpi_dma_request_slave_chan_by_index(dev, 0);
else
fts->rxchan = dma_request_chan(dev, "rx");
if (IS_ERR_OR_NULL(fts->rxchan))
return -ENODEV;

fts->txchan = dma_request_chan(dev, "tx");
if (has_acpi_companion(dev))
fts->txchan = acpi_dma_request_slave_chan_by_index(dev, 1);
else
fts->txchan = dma_request_chan(dev, "tx");
if (IS_ERR_OR_NULL(fts->txchan)) {
dev_err(dev, "can't request chan\n");
dma_release_channel(fts->rxchan);
Expand Down
56 changes: 5 additions & 51 deletions drivers/spi/spi-phytium-plat-v2.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,9 @@
#include "spi-phytium.h"

#define DRIVER_NAME_PHYT "phytium_spi_2.0"
#define DRIVER_VERSION "1.0.8"
#define DRIVER_VERSION "1.0.15"

#define PHYTIUM_CPU_PART_FTC872 0x872

#define MIDR_PHYTIUM_FTC872 MIDR_CPU_MODEL(ARM_CPU_IMP_PHYTIUM, PHYTIUM_CPU_PART_FTC872)

static ssize_t debug_show(struct device *dev,
struct device_attribute *da,
Expand Down Expand Up @@ -129,9 +127,7 @@ static int spi_phyt_probe(struct platform_device *pdev)
struct resource *regfile_mem, *share_mem;
int ret;
int num_cs;
int cs_gpio;
int global_cs = 1;
int i;
u32 clk_rate = SPI_DEFAULT_CLK;

fts = devm_kzalloc(&pdev->dev, sizeof(struct phytium_spi),
Expand Down Expand Up @@ -198,58 +194,16 @@ static int spi_phyt_probe(struct platform_device *pdev)
num_cs = 4;

device_property_read_u32(&pdev->dev, "num-cs", &num_cs);

fts->num_cs = num_cs;

if (pdev->dev.of_node) {
int i;

for (i = 0; i < fts->num_cs; i++) {
cs_gpio = of_get_named_gpio(pdev->dev.of_node,
"cs-gpios", i);

if (cs_gpio == -EPROBE_DEFER) {
ret = cs_gpio;
goto out;
}

if (gpio_is_valid(cs_gpio)) {
ret = devm_gpio_request(&pdev->dev, cs_gpio,
dev_name(&pdev->dev));
if (ret)
goto out;
}
}
} else if (has_acpi_companion(&pdev->dev)) {
int n;
int *cs;
struct gpio_desc *gpiod;

n = gpiod_count(&pdev->dev, "cs");

cs = devm_kcalloc(&pdev->dev, n, sizeof(int), GFP_KERNEL);
fts->cs = cs;

for (i = 0; i < n; i++) {
gpiod = devm_gpiod_get_index_optional(&pdev->dev, "cs", i,
GPIOD_OUT_LOW);

if (IS_ERR(gpiod)) {
ret = PTR_ERR(gpiod);
goto out;
}

cs_gpio = desc_to_gpio(gpiod);
cs[i] = cs_gpio;
}
}

device_property_read_u32(&pdev->dev, "global-cs", &global_cs);
fts->global_cs = global_cs;

fts->dma_get_ddrdata = false;
if ((read_cpuid_id() & MIDR_CPU_MODEL_MASK) == MIDR_PHYTIUM_FTC872)
fts->regfile_version = phytium_read_regfile(fts, SPI_REGFILE_VERSION_REG);
if (fts->regfile_version & SPI_REGFILE_VERSION_DMA)
fts->dma_get_ddrdata = true;
else
fts->dma_get_ddrdata = false;

ret = spi_phyt_add_host(&pdev->dev, fts);
if (ret)
Expand Down
43 changes: 39 additions & 4 deletions drivers/spi/spi-phytium-plat.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
#include "spi-phytium.h"

#define DRIVER_NAME "phytium_spi"
#define DRIVER_VERSION "1.0.0"
#define DRIVER_VERSION "1.0.2"

#define SPI_PHYTIUM_DEFAULT_CLK_RATE 50000000

Expand All @@ -38,6 +38,39 @@ struct phytium_spi_clk {
struct clk *clk;
};

static bool phytium_acpi_has_FixedDMA(struct device *dev)
{
struct acpi_device *adev;
struct acpi_resource *res;
struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
bool found = false;
acpi_status status;

if (!dev)
return false;

adev = ACPI_COMPANION(dev);
if (!adev || !adev->handle)
return false;

/* Get _CRS resource block (kernel allocates buffer) */
status = acpi_get_current_resources(adev->handle, &buf);
if (ACPI_FAILURE(status) || !buf.pointer)
return false;

/* Traverse resource list, exit and return true if FixedDMA is found */
for (res = buf.pointer; res && res->type != ACPI_RESOURCE_TYPE_END_TAG;
res = ACPI_NEXT_RESOURCE(res)) {
if (res->type == ACPI_RESOURCE_TYPE_FIXED_DMA) {
found = true;
break;
}
}

kfree(buf.pointer);
return found;
}

static int phytium_spi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
Expand All @@ -46,7 +79,7 @@ static int phytium_spi_probe(struct platform_device *pdev)
struct resource *mem;
int ret;
int num_cs;
int global_cs = 0;
int global_cs = 1;
u32 clk_rate = SPI_PHYTIUM_DEFAULT_CLK_RATE;

ftsc = devm_kzalloc(&pdev->dev, sizeof(struct phytium_spi_clk),
Expand Down Expand Up @@ -102,8 +135,10 @@ static int phytium_spi_probe(struct platform_device *pdev)

/* check is use dma transfer */
if ((device_property_read_string_array(&pdev->dev, "dma-names",
NULL, 0) > 0) &&
device_property_present(&pdev->dev, "dmas")) {
NULL, 0 > 0) &&
device_property_present(&pdev->dev, "dmas")) ||
(has_acpi_companion(&pdev->dev) &&
phytium_acpi_has_FixedDMA(dev))) {
fts->dma_en = true;
phytium_spi_dmaops_set(fts);
}
Expand Down
Loading