diff options
author | Christian Pointner <equinox@helsinki.at> | 2024-05-10 18:56:00 (GMT) |
---|---|---|
committer | Christian Pointner <equinox@helsinki.at> | 2024-05-10 18:56:00 (GMT) |
commit | af6bfbbd2496b1f5aa02b94caff4e6f988fa32c9 (patch) | |
tree | 45bebb68a0bf3bfc2fff1646f6fa0f4b976fba57 /snd-alpx-dkms/snd-alpx/alpx_mtd.c | |
parent | 7035064ca063fdf15669ceb790ecef1e5ed054b0 (diff) |
rename package to snd-alpx-dkms
Diffstat (limited to 'snd-alpx-dkms/snd-alpx/alpx_mtd.c')
-rw-r--r-- | snd-alpx-dkms/snd-alpx/alpx_mtd.c | 318 |
1 files changed, 318 insertions, 0 deletions
diff --git a/snd-alpx-dkms/snd-alpx/alpx_mtd.c b/snd-alpx-dkms/snd-alpx/alpx_mtd.c new file mode 100644 index 0000000..d0ddd52 --- /dev/null +++ b/snd-alpx-dkms/snd-alpx/alpx_mtd.c @@ -0,0 +1,318 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* +* Support for Digigram AlpX PCI-e boards +* +* Copyright (c) 2024 Digigram Digital (info@digigram.com) +*/ + +#include "alpx_mtd.h" +#include "alpx.h" +#include "alpx_reg.h" + +static const u32 ALPX_FLASH_ERASED_AREA_VALUE = 0xFFFFFFFF; + + +int alpx_mtd_read(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + struct alpx_device *alpx_dev = mtd->priv; + size_t size; + u32 page_index; + u32 offset; + u32 cmd; + int ret; + + page_index = from >> ALPX_FLASH_SECTOR_SHIFT; + offset = from & (ALPX_FLASH_SECTOR_SIZE-1); + + while (len) { + if ((offset + len) > ALPX_FLASH_SECTOR_SIZE) + size = ALPX_FLASH_SECTOR_SIZE - offset; + else + size = len; + + cmd = ALP_PROC_COMMAND_MAKE_P16( + ALP_PROC_CMD_READ_FLASH_SECTOR, page_index); + + dev_dbg(alpx_dev->dev,"Reading %zu bytes Flash sector 0x%x.\n", size, page_index); + + mutex_lock(&alpx_dev->proc_mutex); + ret = alpx_proc_cmd(alpx_dev, cmd); + if (ret) { + mutex_unlock(&alpx_dev->proc_mutex); + dev_err(alpx_dev->dev, + "cmd(CMD_READ_FLASH_SECTOR, 0x%x) failed (%d)\n", + page_index, ret); + + return ret; + } + + memcpy_fromio(buf, ALPX_AREA(alpx_dev, ALP, SHARED) + offset, + size); + mutex_unlock(&alpx_dev->proc_mutex); + + if (retlen) + *retlen += size; + buf += size; + len -= size; + offset = 0; + page_index++; + } + return 0; +} + +int alpx_mtd_write(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) +{ + struct alpx_device *alpx_dev = mtd->priv; + size_t size; + u32 page_index; + u32 offset; + u32 cmd; + int ret; + + page_index = to >> ALPX_FLASH_SECTOR_SHIFT; + offset = to & (ALPX_FLASH_SECTOR_SIZE-1); + + while (len) { + if ((offset + len) > ALPX_FLASH_SECTOR_SIZE) + size = ALPX_FLASH_SECTOR_SIZE - offset; + else + size = len; + + dev_dbg(alpx_dev->dev,"Writing %zu bytes to sector 0x%x.\n", size, page_index); + + mutex_lock(&alpx_dev->proc_mutex); + if (size != ALPX_FLASH_SECTOR_SIZE) { + /* Partial page write -> read modify write*/ + cmd = ALP_PROC_COMMAND_MAKE_P16( + ALP_PROC_CMD_READ_FLASH_SECTOR, page_index); + + ret = alpx_proc_cmd(alpx_dev, cmd); + if (ret) { + mutex_unlock(&alpx_dev->proc_mutex); + dev_err(alpx_dev->dev, + "cmd(CMD_READ_FLASH_SECTOR, 0x%x) failed (%d)\n", + page_index, ret); + return ret; + } + } + + memcpy_toio(ALPX_AREA(alpx_dev, ALP, SHARED) + offset, buf, + size); + + cmd = ALP_PROC_COMMAND_MAKE_P16( + ALP_PROC_CMD_WRITE_FLASH_SECTOR, page_index); + + ret = alpx_proc_cmd(alpx_dev, cmd); + if (ret) { + mutex_unlock(&alpx_dev->proc_mutex); + dev_err(alpx_dev->dev, + "cmd(CMD_WRITE_FLASH_SECTOR, 0x%x) failed (%d)\n", + page_index, ret); + return ret; + } + mutex_unlock(&alpx_dev->proc_mutex); + + if (retlen) + *retlen += size; + buf += size; + len -= size; + offset = 0; + page_index++; + } + return 0; +} + +int alpx_mtd_probe(struct alpx_device *alpx_dev, const struct mtd_partition* partitions, u32 partitions_size) +{ + struct mtd_info *mtd = &alpx_dev->mtd_info; + + /* Setup the MTD structure */ + mtd->type = MTD_RAM; + mtd->flags = MTD_WRITEABLE | MTD_NO_ERASE; + mtd->size = ALPX_FLASH_CHIP_SIZE; + mtd->writesize = ALPX_FLASH_SECTOR_SIZE; + mtd->writebufsize = mtd->writesize; + mtd->priv = alpx_dev; + + mtd->owner = THIS_MODULE; + mtd->dev.parent = alpx_dev->dev; + mtd->_read = alpx_mtd_read; + mtd->_write = alpx_mtd_write; + + return mtd_device_register(mtd, partitions, + partitions_size); +} + +int alpx_mtd_remove(struct alpx_device *alpx_dev) +{ + return alpx_dev->variant->flash_partitions.qty ? mtd_device_unregister(&alpx_dev->mtd_info) : 0; +} + +/* Read one Flash's page into the shared area NO LOCK DONE !!*/ +static int alpx_mtd_load_one_page_into_shared_area(struct alpx_device* alpx_dev, u32 from) +{ + u32 page_index = from >> ALPX_FLASH_SECTOR_SHIFT; + u32 cmd = ALP_PROC_COMMAND_MAKE_P16( + ALP_PROC_CMD_READ_FLASH_SECTOR, page_index); + size_t size = ALPX_FLASH_SECTOR_SIZE; + + int ret; + + /* Check requested length below FLASH sector's size, TODO check page_index too TODO check form is aligned on page */ + if (from % ALPX_FLASH_SECTOR_SIZE != 0) + return -EINVAL; + + dev_dbg(alpx_dev->dev,"Reading %zu bytes Flash sector 0x%x (0x%x).\n", size, page_index, from); + + + ret = alpx_proc_cmd(alpx_dev, cmd); + if (ret) { + dev_err(alpx_dev->dev, + "cmd(CMD_READ_FLASH_SECTOR, 0x%x) failed (%d)\n", + page_index, ret); + return ret; + } + print_hex_dump_bytes("LOADED Shared area :", DUMP_PREFIX_NONE, ALPX_AREA(alpx_dev, ALP, SHARED), 32); + return ret; +} + +/* Store the shared area into the Flash at the to address. NO LOCK DONE */ +static int alpx_mtd_store_one_page_into_shared_area(struct alpx_device* alpx_dev, u32 to) +{ + u32 page_index = to >> ALPX_FLASH_SECTOR_SHIFT; + u32 cmd = ALP_PROC_COMMAND_MAKE_P16( + ALP_PROC_CMD_WRITE_FLASH_SECTOR, page_index); + size_t size = ALPX_FLASH_SECTOR_SIZE; + + int ret; + + print_hex_dump_bytes("STORED Shared area :", DUMP_PREFIX_NONE, ALPX_AREA(alpx_dev, ALP, SHARED), 32); + + /* Check requested length below FLASH sector's size, TODO check page_index too TODO check form is aligned on page */ + if (to % ALPX_FLASH_SECTOR_SIZE != 0) + return -EINVAL; + + dev_dbg(alpx_dev->dev,"Storing %zu bytes to Flash sector 0x%x.\n", size, page_index); + + ret = alpx_proc_cmd(alpx_dev, cmd); + if (ret) { + dev_err(alpx_dev->dev, + "cmd(ALP_PROC_CMD_WRITE_FLASH_SECTOR, 0x%x) failed (%d)\n", + page_index, ret); + return ret; + } + + return ret; +} + +int alpx_mtd_is_golden_prod_area_valid(struct alpx_device* alpx_dev) +{ + int ret = 0; + + mutex_lock(&alpx_dev->proc_mutex); + ret = alpx_mtd_load_one_page_into_shared_area(alpx_dev, alpx_dev->variant->flash_golden_production_base); + + if (!ret) { + //Now check Production area validity per se : something set in and not in erased state + ret = (*(u32*)ALPX_AREA(alpx_dev, ALP, SHARED)) != ALPX_FLASH_ERASED_AREA_VALUE; + } + else { + dev_err(alpx_dev->dev, "Error %d when loading shared area from flash.\n", ret); + } + mutex_unlock(&alpx_dev->proc_mutex); + return ret; +} + +int alpx_mtd_replicate_prod_area(struct alpx_device* alpx_dev) +{ + /* Read the USER's Production area and then write it to the GOLDEN'sProduction area */ + //Read User + + int ret = 0; + mutex_lock(&alpx_dev->proc_mutex); + + ret= alpx_mtd_load_one_page_into_shared_area(alpx_dev, + alpx_dev->variant->flash_partitions.partitions[ALPX_FLASH_PARTITION_PRODUCTION_ID].offset); + if (!ret) { + //Write it to the GOLDEN's area + ret = alpx_mtd_store_one_page_into_shared_area(alpx_dev, alpx_dev->variant->flash_golden_production_base); + if (ret) { + dev_err(alpx_dev->dev,"Error %d when storing the USER's Production area into GOLDEN.\n", ret); + } + } + else { + dev_err(alpx_dev->dev,"Error %d when reading the USER's Production area.\n", ret); + } + + mutex_unlock(&alpx_dev->proc_mutex); + return ret; +} + +int alpx_mtd_read_from(struct alpx_device* alpx_dev, + uint32_t from, + unsigned char* to, + unsigned int length) +{ + int ret = 0; + + //Check : never read more than SHARE area length + if (length > ALP_SHARED_SIZE) + return -EINVAL; + + mutex_lock(&alpx_dev->proc_mutex); + //Load the PRODUCTION into the shared AREA, then extract the Serial Number + ret= alpx_mtd_load_one_page_into_shared_area(alpx_dev, from); + + if (!ret) { + unsigned int idx = 0; + //NO memcpy() when dealing with SHARED Area + for (idx = 0 ; idx < length; ++idx) { + to[idx] = *(((unsigned char*)ALPX_AREA(alpx_dev, ALP, SHARED))+idx); + } + print_hex_dump_bytes("READ:", DUMP_PREFIX_NONE, to, length); + } else { + dev_err(alpx_dev->dev, " Error 0x%x when reading Flash memory at %d.\n", ret, from); + } + + mutex_unlock(&alpx_dev->proc_mutex); + + return ret; +} + +int alpx_mtd_load_shared_from(struct alpx_device* alpx_dev, uint32_t from) +{ + //Only one page at the moment, must be ALP_SHARED_SIZE bytes after. + return alpx_mtd_load_one_page_into_shared_area(alpx_dev, from); +} + +int alpx_mtd_read_shared(struct alpx_device* alpx_dev, + uint32_t at, + unsigned char* to, + unsigned int length) +{ + unsigned int idx; + //NO memcpy() when dealing with SHARED Area + for (idx = 0 ; idx < length; ++idx) { + to[idx] = *(((unsigned char*)ALPX_AREA(alpx_dev, ALP, SHARED))+idx + at); + } + print_hex_dump_bytes("READ:", DUMP_PREFIX_NONE, to, length); + return 0; +} + +int alpx_mtd_clean_shared(struct alpx_device* alpx_dev) +{ + unsigned int idx; + //NO memcpy() when dealing with SHARED Area + for (idx = 0 ; idx < (ALPX_FLASH_SECTOR_SIZE / sizeof(unsigned int)); ++idx) { + *(unsigned int*)(ALPX_AREA(alpx_dev, ALP, SHARED)+idx) = 0; + } + return 0; +} + +int alpx_mtd_is_available(struct alpx_device* alpx_dev) +{ + //DANTE : no MTD available yet + return alpx_dev->variant->model != ALPX_VARIANT_MODEL_ALPDANTE; +} |