Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(kernel-rolling) spi: qspi: Add Phytium spi/qspi controller support #210

Closed
70 changes: 70 additions & 0 deletions Documentation/devicetree/bindings/spi/phytium,qspi-nor.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/spi/phytium,qspi-nor.yaml#
$schema: http://devicetree.org/schemas/meta-schemas/core.yaml#

title: Phytium Quad Serial Peripheral Interface (QSPI) bindings

maintainers:
- Chen Baozi <[email protected]>

allOf:
- $ref: "spi-controller.yaml#"

properties:
compatible:
const: phytium,qspi-nor

reg:
items:
- description: registers
- description: memory mapping region

reg-names:
items:
- const: qspi
- const: qspi_mm

clocks:
maxItems: 1

no-direct-mapping:
$ref: /schemas/types.yaml#/definitions/flag
description:
Indicates if we can use direct mapping to access the flash

required:
- compatible
- reg
- reg-names
- clocks

unevaluateProperties: false

examples:
- |
qspi: qspi@28014000 {
compatible = "phytium,qspi-nor";
reg = <0x0 0x28014000 0x0 0x1000>,
<0x0 0x0 0x0 0x02000000>;
reg-names = "qspi", "qspi_mm";
clocks = <&sysclk_600mhz>;

#address-cells = <1>;
#size-cells = <0>;

flash@0 {
compatible = "jedec,spi-nor";
reg = <0>;
spi-rx-bus-width = <4>;
spi-max-frequency = <600000000>;
};

flash@1 {
compatible = "jedec,spi-nor";
reg = <1>;
spi-rx-bus-width = <4>;
spi-max-frequency = <600000000>;
};
};
49 changes: 49 additions & 0 deletions Documentation/devicetree/bindings/spi/phytium,spi.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/spi/phytium,spi.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: Phytium SPI controller

maintainers:
- Chen Baozi <[email protected]>

allOf:
- $ref: spi-controller.yaml#

properties:
compatible:
const: phytium,spi

reg:
minItems: 1
description: address and length of the spi master registers

interrupts:
maxItems: 1
description: should contain one interrupt

clocks:
maxItems: 1
description: spi clock phandle

required:
- compatible
- "#address-cells"
- "#size-cells"
- reg
- interrupts
- clocks
- num-cs

examples:
- |

spi0: spi@2800c000 {
compatible = "phytium,spi";
interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>;
reg = <0x0 0x2800c000 0x0 0x1000>;
clocks = <&sysclk_48mhz>;
num-cs = <4>;
};
44 changes: 43 additions & 1 deletion drivers/mtd/mtdpart.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
#include <linux/of.h>
#include <linux/of_platform.h>

#include <linux/acpi.h>
#include <linux/property.h>
#include "mtdcore.h"

/*
Expand Down Expand Up @@ -508,12 +510,14 @@ EXPORT_SYMBOL_GPL(deregister_mtd_parser);
static const char * const default_mtd_part_types[] = {
"cmdlinepart",
"ofpart",
"acpipart",
NULL
};

/* Check DT only when looking for subpartitions. */
static const char * const default_subpartition_types[] = {
"ofpart",
"acpipart",
NULL
};

Expand Down Expand Up @@ -577,6 +581,42 @@ static struct mtd_part_parser *mtd_part_get_compatible_parser(const char *compat
return ret;
}

static int mtd_part_acpi_parse(struct mtd_info *master,
struct mtd_partitions *pparts)
{
struct mtd_part_parser *parser;
struct fwnode_handle *child;
const char *compat;
const char *fixed = "acpi-fixed-partitions";
int ret, err = 0;
int compare = 1;
struct device *dev = &master->dev;

if (!mtd_is_partition(master)) {
fwnode_property_read_string(dev->fwnode, "fixed", &compat);
if (compat)
compare = strcmp(compat, fixed);
}

//all child node
device_for_each_child_node(dev, child) {
if (compat && !compare) {
parser = mtd_part_parser_get(fixed);
if (!parser && !request_module("%s", fixed))
parser = mtd_part_parser_get(fixed);
if (parser) {
ret = mtd_part_do_parse(parser, master, pparts, NULL);
if (ret > 0)
return ret;
mtd_part_parser_put(parser);
if (ret < 0 && !err)
err = ret;
}
}
}
return err;
}

static int mtd_part_of_parse(struct mtd_info *master,
struct mtd_partitions *pparts)
{
Expand Down Expand Up @@ -682,7 +722,9 @@ int parse_mtd_partitions(struct mtd_info *master, const char *const *types,
* should be used. It requires a bit different logic so it is
* handled in a separated function.
*/
if (!strcmp(*types, "ofpart")) {
if (!strcmp(*types, "acpipart")) {
ret = mtd_part_acpi_parse(master, &pparts);
} else if (!strcmp(*types, "ofpart")) {
ret = mtd_part_of_parse(master, &pparts);
} else {
pr_debug("%s: parsing partitions %s\n", master->name,
Expand Down
8 changes: 8 additions & 0 deletions drivers/mtd/parsers/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,14 @@ config MTD_OF_PARTS_LINKSYS_NS
two "firmware" partitions. Currently used firmware has to be detected
using CFE environment variable.

config MTD_ACPI_PARTS
tristate "ACPI partitioning parser"
depends on ACPI && (ARCH_PHYTIUM || COMPILE_TEST)
help
This provides an acpi partition parser, which is used to parse the
partition map described in ACPI table, as the children of the flash
memory struct.

config MTD_PARSER_IMAGETAG
tristate "Parser for BCM963XX Image Tag format partitions"
depends on BCM63XX || BMIPS_GENERIC || COMPILE_TEST
Expand Down
2 changes: 2 additions & 0 deletions drivers/mtd/parsers/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o
ofpart-y += ofpart_core.o
ofpart-$(CONFIG_MTD_OF_PARTS_BCM4908) += ofpart_bcm4908.o
ofpart-$(CONFIG_MTD_OF_PARTS_LINKSYS_NS)+= ofpart_linksys_ns.o
obj-$(CONFIG_MTD_ACPI_PARTS) += acpipart.o
acpipart-y += acpipart_core.o
obj-$(CONFIG_MTD_PARSER_IMAGETAG) += parser_imagetag.o
obj-$(CONFIG_MTD_AFS_PARTS) += afs.o
obj-$(CONFIG_MTD_PARSER_TPLINK_SAFELOADER) += tplink_safeloader.o
Expand Down
143 changes: 143 additions & 0 deletions drivers/mtd/parsers/acpipart_core.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Flash partitions described by the acpi table
*
* Author: Wang Hanmo <[email protected]>
*/

#include <linux/module.h>
#include <linux/init.h>
#include <linux/mtd/mtd.h>
#include <linux/slab.h>
#include <linux/mtd/partitions.h>
#include <linux/property.h>
#include <linux/acpi.h>

static const struct acpi_device_id parse_acpipart_match_table[];

static int parse_acpi_fixed_partitions(struct mtd_info *master,
const struct mtd_partition **pparts,
struct mtd_part_parser_data *data)
{
struct mtd_partition *parts;
struct acpi_device_id *acpi_id;
const char *partname;
int nr_parts, i, ret = 0;
struct acpi_device *adev;
struct fwnode_handle *child;
struct fwnode_handle *child_handle;
bool dedicated = true;
struct device *dev;

dev = &master->dev;
adev = ACPI_COMPANION(&master->dev);

if (!master->parent) {/*master*/
device_get_next_child_node(dev, child_handle);
if (!child_handle) {
pr_debug("%s: 'partitions' subnode not found on %pOF. Trying to parse direct subnodes as partitions.\n",
master->name, child_handle);
dedicated = false;
}
}

acpi_id = acpi_match_device(parse_acpipart_match_table, dev);
if (dedicated && !acpi_id)
return 0;

nr_parts = 0;
device_for_each_child_node(dev, child_handle) {
nr_parts++;
}

if (nr_parts == 0)
return 0;
parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL);
if (!parts)
return -ENOMEM;

i = 0;
device_for_each_child_node(dev, child_handle) {
u64 offset, length;
bool bool_match;

fwnode_property_read_u64(child_handle, "offset", &offset);
fwnode_property_read_u64(child_handle, "length", &length);
if (!offset && !length) {
if (dedicated) {
pr_debug("%s: acpipart partition %pOF (%pOF) missing reg property.\n",
master->name, child_handle,
dev->fwnode);
goto acpipart_fail;
} else {
nr_parts--;
continue;
}
}

parts[i].offset = offset;
parts[i].size = length;
parts[i].fwnode = child_handle;
if (!fwnode_property_read_string(child_handle, "label", &partname))
parts[i].name = partname;
bool_match = fwnode_property_read_bool(child_handle, "read-only");
if (bool_match)
parts[i].mask_flags |= MTD_WRITEABLE;
bool_match = fwnode_property_read_bool(child_handle, "lock");
if (bool_match)
parts[i].mask_flags |= MTD_POWERUP_LOCK;
bool_match = fwnode_property_read_bool(child_handle, "slc-mode");
if (bool_match)
parts[i].mask_flags |= MTD_SLC_ON_MLC_EMULATION;
i++;
}

if (!nr_parts)
goto acpipart_none;

*pparts = parts;
ret = nr_parts;
return ret;

acpipart_fail:
pr_err("%s: error parsing acpipart partition %pOF (%pOF)\n",
master->name, child_handle, dev->fwnode);
ret = -EINVAL;
acpipart_none:
kfree(parts);
return ret;
}

static const struct acpi_device_id parse_acpipart_match_table[] = {
/* Generic */
{ "acpi-fixed-partitions", 0 },
/* Customized */
{},
};

MODULE_DEVICE_TABLE(acpi, parse_acpipart_match_table);

static struct mtd_part_parser acpipart_parser = {
.parse_fn = parse_acpi_fixed_partitions,
.name = "acpi-fixed-partitions",
.acpi_match_table = ACPI_PTR(parse_acpipart_match_table),
};

static int __init acpipart_parser_init(void)
{
register_mtd_parser(&acpipart_parser);
return 0;
}

static void __exit acpipart_parser_exit(void)
{
deregister_mtd_parser(&acpipart_parser);
}

module_init(acpipart_parser_init);
module_exit(acpipart_parser_exit);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Parser for MTD partitioning information in acpi table");
MODULE_AUTHOR("wanghanmo <[email protected]>");
MODULE_ALIAS("acpi-fixed-partitions");
Loading