* [PATCH 0/3] of/overlay: sysfs based ABI for dt overlays
From: Heinrich Schuchardt @ 2016-12-19 1:10 UTC (permalink / raw)
To: Rob Herring, Mark Rutland, Frank Rowand
Cc: devicetree, linux-kernel, Heinrich Schuchardt
Currently the kernel only supplies an internal API for creating
and destroying device tree overlays.
For some boards vendor specific kernel modules exist for
managing device tree overlays but they have not been
upstreamed or upstreaming stalled.
https://lkml.org/lkml/2015/6/12/624
https://lkml.org/lkml/2013/1/7/366
This patch series provides a sysfs based ABI for creation and
destruction of dt overlays in /sys/firmware/devicetree-overlay.
The following files are provided:
load: This is a write only file.
A string written to it is interpreted as the path to a
flattened device tree overlay file. It is used to create
and apply the contained overlays.
loaded: This is a read only file.
It provides the count of loaded overlays as a decimal
number.
unload: This is a write only file.
If a positive number n is wrtten to this file the n
most recent overlays are destroyed.
If a negative number is written to this file all
overlays are destroyed.
Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Heinrich Schuchardt (3):
of/overlay: add API function to count and pop last
of/overlay: sysfs based ABI for dt overlays
of/overlay: documentation for sysfs ABI
.../ABI/testing/sysfs-firmware-devicetree-overlays | 24 +++
Documentation/devicetree/overlay-notes.txt | 7 +-
drivers/of/Kconfig | 12 ++
drivers/of/Makefile | 2 +
drivers/of/ov_sysfs.c | 212 +++++++++++++++++++++
drivers/of/overlay.c | 50 +++++
include/linux/of.h | 12 ++
7 files changed, 317 insertions(+), 2 deletions(-)
create mode 100644 Documentation/ABI/testing/sysfs-firmware-devicetree-overlays
create mode 100644 drivers/of/ov_sysfs.c
--
2.11.0
^ permalink raw reply
* [PATCH 1/3] of/overlay: add API function to count and pop last
From: Heinrich Schuchardt @ 2016-12-19 1:10 UTC (permalink / raw)
To: Rob Herring, Mark Rutland, Frank Rowand
Cc: devicetree, linux-kernel, Heinrich Schuchardt
In-Reply-To: <1482109835-9000-1-git-send-email-xypron.glpk@gmx.de>
To allow building interfaces which are not id based
two new functions are added to the device tree
overlay API:
of_overlay_count - counts the loaded overlays
of_overlay_destroy_last - removes the last overlay loaded
Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
---
Documentation/devicetree/overlay-notes.txt | 7 +++--
drivers/of/overlay.c | 50 ++++++++++++++++++++++++++++++
include/linux/of.h | 12 +++++++
3 files changed, 67 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/overlay-notes.txt b/Documentation/devicetree/overlay-notes.txt
index d418a6ce9812..7c8099c81e91 100644
--- a/Documentation/devicetree/overlay-notes.txt
+++ b/Documentation/devicetree/overlay-notes.txt
@@ -89,17 +89,20 @@ Overlay in-kernel API
The API is quite easy to use.
-1. Call of_overlay_create() to create and apply an overlay. The return value
+Call of_overlay_create() to create and apply an overlay. The return value
is a cookie identifying this overlay.
-2. Call of_overlay_destroy() to remove and cleanup the overlay previously
+Call of_overlay_destroy() to remove and cleanup the overlay previously
created via the call to of_overlay_create(). Removal of an overlay that
is stacked by another will not be permitted.
+Or call of_overlay_destroy_last() to remove the most recent overlay.
Finally, if you need to remove all overlays in one-go, just call
of_overlay_destroy_all() which will remove every single one in the correct
order.
+Call of_overlay_count() to determine the number of loaded overlays.
+
Overlay DTS Format
------------------
diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
index 0d4cda7050e0..bd30253b26f9 100644
--- a/drivers/of/overlay.c
+++ b/drivers/of/overlay.c
@@ -587,3 +587,53 @@ int of_overlay_destroy_all(void)
return 0;
}
EXPORT_SYMBOL_GPL(of_overlay_destroy_all);
+
+/**
+ * of_overlay_destroy_last() - Removes the last overlay from the system
+ *
+ * It is allways possible to delete the last overlay.
+ *
+ * Returns 0 on success, or a negative error number
+ */
+int of_overlay_destroy_last(void)
+{
+ struct of_overlay *ov, *ovn;
+ int id;
+
+ mutex_lock(&of_mutex);
+
+ list_for_each_entry_safe_reverse(ov, ovn, &ov_list, node) {
+ id = ov->id;
+ mutex_unlock(&of_mutex);
+ return of_overlay_destroy(id);
+ }
+
+ mutex_unlock(&of_mutex);
+
+ pr_info("destroy: No overlay to destroy");
+
+ return -ENODEV;
+}
+EXPORT_SYMBOL_GPL(of_overlay_destroy_last);
+
+/**
+ * of_overlay_count - Counts number of loaded overlays
+ *
+ * Returns number of loaded overlays
+ */
+int of_overlay_count(void)
+{
+ struct of_overlay *ov, *ovn;
+ int count = 0;
+
+ mutex_lock(&of_mutex);
+
+ list_for_each_entry_safe(ov, ovn, &ov_list, node) {
+ ++count;
+ }
+
+ mutex_unlock(&of_mutex);
+
+ return count;
+}
+EXPORT_SYMBOL_GPL(of_overlay_count);
diff --git a/include/linux/of.h b/include/linux/of.h
index d72f01009297..73c8826c543b 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -1281,15 +1281,22 @@ struct of_overlay_notify_data {
#ifdef CONFIG_OF_OVERLAY
/* ID based overlays; the API for external users */
+int of_overlay_count(void);
int of_overlay_create(struct device_node *tree);
int of_overlay_destroy(int id);
int of_overlay_destroy_all(void);
+int of_overlay_destroy_last(void);
int of_overlay_notifier_register(struct notifier_block *nb);
int of_overlay_notifier_unregister(struct notifier_block *nb);
#else
+static int of_overlay_count(void)
+{
+ return -ENOTSUPP;
+}
+
static inline int of_overlay_create(struct device_node *tree)
{
return -ENOTSUPP;
@@ -1305,6 +1312,11 @@ static inline int of_overlay_destroy_all(void)
return -ENOTSUPP;
}
+static inline int of_overlay_destroy_last(void)
+{
+ return -ENOTSUPP;
+}
+
static inline int of_overlay_notifier_register(struct notifier_block *nb)
{
return 0;
--
2.11.0
^ permalink raw reply related
* [PATCH 2/3] of/overlay: sysfs based ABI for dt overlays
From: Heinrich Schuchardt @ 2016-12-19 1:10 UTC (permalink / raw)
To: Rob Herring, Mark Rutland, Frank Rowand
Cc: devicetree, linux-kernel, Heinrich Schuchardt
In-Reply-To: <1482109835-9000-1-git-send-email-xypron.glpk@gmx.de>
Currently the kernel only supplies an internal API for creating
and destroying device tree overlays.
For some boards vendor specific kernel modules exist for
managing device tree overlays but the have not been
upstreamed.
This patch provides a sysfs based ABI for creation and destruction
of dt overlays in /sys/firmware/devicetree-overlay.
The following files are provided:
load: This is a write only file.
A string written to it is interpreted as the path to a
flattened device tree overlay file. It is used to create
and apply the contained overlays.
loaded: This is a read only file.
It provides the count of loaded overlays as a decimal
number.
unload: This is a write only file.
If a positive number n is wrtten to this file the n
most recent overlays are destroyed.
If a negative number is written to this file all
overlays are destroyed.
Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
---
drivers/of/Kconfig | 14 ++++
drivers/of/Makefile | 2 +
drivers/of/ov_sysfs.c | 214 ++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 230 insertions(+)
create mode 100644 drivers/of/ov_sysfs.c
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index ba7b034b2b91..c981a7e84bcb 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -109,6 +109,20 @@ config OF_OVERLAY
While this option is selected automatically when needed, you can
enable it manually to improve device tree unit test coverage.
+if OF_OVERLAY
+
+config OF_OVERLAY_SYSFS
+
+ tristate "Sysfs support for device tree overlays"
+ default m
+ depends on SYSFS
+ help
+ This module provides a sysfs based ABI to manage device tree
+ overlays. You can use it to create overlays based on flattened
+ device tree overlay files and to destroy them.
+
+endif # OF_OVERLAY
+
config OF_NUMA
bool
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index d7efd9d458aa..7026de457a04 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -16,3 +16,5 @@ obj-$(CONFIG_OF_OVERLAY) += overlay.o
obj-$(CONFIG_OF_NUMA) += of_numa.o
obj-$(CONFIG_OF_UNITTEST) += unittest-data/
+
+obj-$(CONFIG_OF_OVERLAY_SYSFS) += ov_sysfs.o
diff --git a/drivers/of/ov_sysfs.c b/drivers/of/ov_sysfs.c
new file mode 100644
index 000000000000..eb1b8fd4bc32
--- /dev/null
+++ b/drivers/of/ov_sysfs.c
@@ -0,0 +1,214 @@
+/*
+ * Sysfs ABI for device tree overlays
+ *
+ * Copyright (C) 2016 Heinrich Schuchardt <xypron.glpk@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License,
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#include <linux/fcntl.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/libfdt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/uaccess.h>
+
+static int of_create_overlay_from_file(const char *path)
+{
+ struct file *filp = NULL;
+ mm_segment_t fs;
+ int ret = 0;
+ loff_t size;
+ char *buffer = NULL;
+ ssize_t bytes_read;
+ loff_t offset = 0;
+ struct device_node *overlay = NULL;
+
+ fs = get_fs();
+ set_fs(get_ds());
+ filp = filp_open(path, O_RDONLY | O_LARGEFILE, 0);
+ if (IS_ERR(filp)) {
+ ret = PTR_ERR(filp);
+ goto err_file_open;
+ }
+
+ if (!S_ISREG(filp->f_inode->i_mode)) {
+ ret = -EISDIR;
+ goto err_file_read;
+ }
+ size = i_size_read(filp->f_inode);
+ buffer = vmalloc(size);
+ if (buffer == NULL) {
+ ret = -ENOMEM;
+ goto err_malloc;
+ }
+ for (; size > 0; ) {
+ bytes_read = vfs_read(filp, buffer, size, &offset);
+ if (bytes_read == 0)
+ break;
+ if (bytes_read < 0) {
+ ret = bytes_read;
+ goto err_file_read;
+ }
+ size -= bytes_read;
+ }
+ if (offset < sizeof(struct fdt_header) ||
+ offset < fdt_totalsize(buffer)) {
+ pr_err("OF: Size of %s does not match header information\n",
+ path);
+ ret = -EINVAL;
+ goto err_file_read;
+ }
+ overlay = of_fdt_unflatten_tree((unsigned long *) buffer, NULL, NULL);
+ if (overlay == NULL) {
+ pr_err("OF: Cannot unflatten %s\n", path);
+ ret = -EINVAL;
+ goto err_file_read;
+ }
+ of_node_set_flag(overlay, OF_DETACHED);
+ ret = of_resolve_phandles(overlay);
+ if (ret < 0) {
+ pr_err("OF: Failed to resolve phandles for %s\n", path);
+ goto err_overlay;
+ }
+ ret = of_overlay_create(overlay);
+ if (ret < 0) {
+ pr_err("OF: Cannot create overlay from %s\n", path);
+ } else {
+ pr_info("OF: Overlay %d created from %s\n", ret, path);
+ ret = 0;
+ }
+err_overlay:
+ of_node_put(overlay);
+err_file_read:
+ vfree(buffer);
+err_malloc:
+ fput(filp);
+err_file_open:
+ set_fs(fs);
+ return ret;
+}
+
+static ssize_t attribute_read(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ int ret;
+
+ if (strcmp(attr->attr.name, "loaded") == 0)
+ ret = sprintf(buf, "%d\n", of_overlay_count());
+ else
+ ret = -ENOENT;
+
+ return ret;
+}
+
+static ssize_t attribute_write(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t size)
+{
+ char *parameter;
+ int ret;
+ long count;
+
+ if (size > PATH_MAX)
+ return -ENAMETOOLONG;
+
+ /* The parameter has to be terminated either by LF or \0. */
+
+ switch (buf[size - 1]) {
+ case 0x00:
+ case 0x0a:
+ break;
+ default:
+ return -ENOENT;
+ }
+ parameter = vmalloc(size);
+ if (!parameter)
+ return -ENOMEM;
+ memcpy(parameter, buf, size);
+ parameter[size - 1] = 0x00;
+
+ if (strcmp(attr->attr.name, "load") == 0) {
+ ret = of_create_overlay_from_file(parameter);
+ if (!ret)
+ ret = size;
+ } else if (strcmp(attr->attr.name, "unload") == 0) {
+ ret = kstrtol(parameter, 0, &count);
+ if (ret)
+ goto out;
+ if (count < 0)
+ ret = of_overlay_destroy_all();
+ else
+ for (; count > 0; --count) {
+ ret = of_overlay_destroy_last();
+ if (ret)
+ goto out;
+ }
+ ret = size;
+ } else
+ ret = -ENOENT;
+out:
+ vfree(parameter);
+
+ return ret;
+}
+
+static struct kobject *kobj;
+
+static struct kobj_attribute load_attribute =
+ __ATTR(load, 0200, NULL, attribute_write);
+static struct kobj_attribute loaded_attribute =
+ __ATTR(loaded, 0444, attribute_read, NULL);
+static struct kobj_attribute unload_attribute =
+ __ATTR(unload, 0200, NULL, attribute_write);
+static struct attribute *attrs[] = {
+ &load_attribute.attr,
+ &loaded_attribute.attr,
+ &unload_attribute.attr,
+ NULL
+};
+static struct attribute_group attr_group = {
+ .attrs = attrs,
+};
+
+static int __init ov_sysfs_init(void)
+{
+ int ret;
+
+ kobj = kobject_create_and_add("devicetree-overlays", firmware_kobj);
+ if (kobj == 0)
+ return -ENOMEM;
+ ret = sysfs_create_group(kobj, &attr_group);
+ if (ret) {
+ kobject_put(kobj);
+ return ret;
+ }
+
+ /*
+ * It is not possible to ensure that no sysfs io is started while
+ * module_exit is called. So disable unloading.
+ */
+ __module_get(THIS_MODULE);
+
+ return 0;
+}
+
+static void __exit ov_sysfs_exit(void)
+{
+ kobject_put(kobj);
+}
+
+module_init(ov_sysfs_init);
+module_exit(ov_sysfs_exit);
+
+MODULE_AUTHOR("Heinrich Schuchardt <xypron.glpk@gmx.de>");
+MODULE_DESCRIPTION("Sysfs ABI for device tree overlays");
+MODULE_LICENSE("GPL");
--
2.11.0
^ permalink raw reply related
* [PATCH 3/3] of/overlay: documentation for sysfs ABI
From: Heinrich Schuchardt @ 2016-12-19 1:10 UTC (permalink / raw)
To: Rob Herring, Mark Rutland, Frank Rowand
Cc: devicetree, linux-kernel, Heinrich Schuchardt
In-Reply-To: <1482109835-9000-1-git-send-email-xypron.glpk@gmx.de>
The sysfs filesystem ABI to load and unload devicetree
overlays is decribed.
Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
---
.../ABI/testing/sysfs-firmware-devicetree-overlays | 24 ++++++++++++++++++++++
1 file changed, 24 insertions(+)
create mode 100644 Documentation/ABI/testing/sysfs-firmware-devicetree-overlays
diff --git a/Documentation/ABI/testing/sysfs-firmware-devicetree-overlays b/Documentation/ABI/testing/sysfs-firmware-devicetree-overlays
new file mode 100644
index 000000000000..ce25b637028c
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-firmware-devicetree-overlays
@@ -0,0 +1,24 @@
+What: /sys/firmware/devicetree-overlays
+Date: Dec 2016
+KernelVersion: 4.11
+Contact: Heinrich Schuchardt <xypron.glpk@gmx.de>
+Description: Devicetree overlays can be used to update the devicetree
+ while the system is running. For details see
+ Documentation/devicetree/overlay-notes.txt.
+
+ The following attributes are provided:
+
+ load: This is a write only file.
+ A string written to it is interpreted as the path to a
+ flattened device tree overlay file. It is used to create
+ and apply the contained overlays.
+
+ loaded: This is a read only file.
+ It provides the count of loaded overlays as a decimal
+ number.
+
+ unload: This is a write only file.
+ If a positive number n is wrtten to this file the n
+ most recent overlays are destroyed.
+ If a negative number is written to this file all
+ overlays are destroyed.
--
2.11.0
^ permalink raw reply related
* [PATCH v2 0/4] clk: rockchip: support clk controller for rk3328 SoC
From: Elaine Zhang @ 2016-12-19 1:56 UTC (permalink / raw)
To: heiko, mturquette, sboyd, xf
Cc: robh+dt, mark.rutland, linux-clk, linux-arm-kernel, devicetree,
huangtao, xxx, cl, linux-rockchip, linux-kernel, Elaine Zhang
Changes in v2:
add bindings for rk3328 clock controller
Elaine Zhang (4):
clk: rockchip: add dt-binding header for rk3328
dt-bindings: add bindings for rk3328 clock controller
clk: rockchip: add clock controller for rk3328
clk: rockchip: add new pll-type for rk3328
.../bindings/clock/rockchip,rk3328-cru.txt | 57 ++
drivers/clk/rockchip/Makefile | 1 +
drivers/clk/rockchip/clk-pll.c | 13 +-
drivers/clk/rockchip/clk-rk3328.c | 1068 ++++++++++++++++++++
drivers/clk/rockchip/clk.h | 23 +
include/dt-bindings/clock/rk3328-cru.h | 403 ++++++++
6 files changed, 1564 insertions(+), 1 deletion(-)
create mode 100644 Documentation/devicetree/bindings/clock/rockchip,rk3328-cru.txt
create mode 100644 drivers/clk/rockchip/clk-rk3328.c
create mode 100644 include/dt-bindings/clock/rk3328-cru.h
--
1.9.1
^ permalink raw reply
* [PATCH v2 1/4] clk: rockchip: add dt-binding header for rk3328
From: Elaine Zhang @ 2016-12-19 1:56 UTC (permalink / raw)
To: heiko, mturquette, sboyd, xf
Cc: robh+dt, mark.rutland, linux-clk, linux-arm-kernel, devicetree,
huangtao, xxx, cl, linux-rockchip, linux-kernel, Elaine Zhang
In-Reply-To: <1482112573-11613-1-git-send-email-zhangqing@rock-chips.com>
Add the dt-bindings header for the rk3328, that gets shared between
the clock controller and the clock references in the dts.
Add softreset ID for rk3328.
Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
---
include/dt-bindings/clock/rk3328-cru.h | 403 +++++++++++++++++++++++++++++++++
1 file changed, 403 insertions(+)
create mode 100644 include/dt-bindings/clock/rk3328-cru.h
diff --git a/include/dt-bindings/clock/rk3328-cru.h b/include/dt-bindings/clock/rk3328-cru.h
new file mode 100644
index 000000000000..545ed7541316
--- /dev/null
+++ b/include/dt-bindings/clock/rk3328-cru.h
@@ -0,0 +1,403 @@
+/*
+ * Copyright (c) 2016 Rockchip Electronics Co. Ltd.
+ * Author: Elaine <zhangqing@rock-chips.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that 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.
+ */
+
+#ifndef _DT_BINDINGS_CLK_ROCKCHIP_RK3328_H
+#define _DT_BINDINGS_CLK_ROCKCHIP_RK3328_H
+
+/* core clocks */
+#define PLL_APLL 1
+#define PLL_DPLL 2
+#define PLL_CPLL 3
+#define PLL_GPLL 4
+#define PLL_NPLL 5
+#define ARMCLK 6
+
+/* sclk gates (special clocks) */
+#define SCLK_RTC32K 30
+#define SCLK_SDMMC_EXT 31
+#define SCLK_SPI 32
+#define SCLK_SDMMC 33
+#define SCLK_SDIO 34
+#define SCLK_EMMC 35
+#define SCLK_TSADC 36
+#define SCLK_SARADC 37
+#define SCLK_UART0 38
+#define SCLK_UART1 39
+#define SCLK_UART2 40
+#define SCLK_I2S0 41
+#define SCLK_I2S1 42
+#define SCLK_I2S2 43
+#define SCLK_I2S1_OUT 44
+#define SCLK_I2S2_OUT 45
+#define SCLK_SPDIF 46
+#define SCLK_TIMER0 47
+#define SCLK_TIMER1 48
+#define SCLK_TIMER2 49
+#define SCLK_TIMER3 50
+#define SCLK_TIMER4 51
+#define SCLK_TIMER5 52
+#define SCLK_WIFI 53
+#define SCLK_CIF_OUT 54
+#define SCLK_I2C0 55
+#define SCLK_I2C1 56
+#define SCLK_I2C2 57
+#define SCLK_I2C3 58
+#define SCLK_CRYPTO 59
+#define SCLK_PWM 60
+#define SCLK_PDM 61
+#define SCLK_EFUSE 62
+#define SCLK_OTP 63
+#define SCLK_DDRCLK 64
+#define SCLK_VDEC_CABAC 65
+#define SCLK_VDEC_CORE 66
+#define SCLK_VENC_DSP 67
+#define SCLK_VENC_CORE 68
+#define SCLK_RGA 69
+#define SCLK_HDMI_SFC 70
+#define SCLK_HDMI_CEC 71
+#define SCLK_USB3_REF 72
+#define SCLK_USB3_SUSPEND 73
+#define SCLK_SDMMC_DRV 74
+#define SCLK_SDIO_DRV 75
+#define SCLK_EMMC_DRV 76
+#define SCLK_SDMMC_EXT_DRV 77
+#define SCLK_SDMMC_SAMPLE 78
+#define SCLK_SDIO_SAMPLE 79
+#define SCLK_EMMC_SAMPLE 80
+#define SCLK_SDMMC_EXT_SAMPLE 81
+#define SCLK_VOP 82
+#define SCLK_MAC2PHY_RXTX 83
+#define SCLK_MAC2PHY_SRC 84
+#define SCLK_MAC2PHY_REF 85
+#define SCLK_MAC2PHY_OUT 86
+#define SCLK_MAC2IO_RX 87
+#define SCLK_MAC2IO_TX 88
+#define SCLK_MAC2IO_REFOUT 89
+#define SCLK_MAC2IO_REF 90
+#define SCLK_MAC2IO_OUT 91
+#define SCLK_TSP 92
+#define SCLK_HSADC_TSP 93
+#define SCLK_USB3PHY_REF 94
+#define SCLK_REF_USB3OTG 95
+#define SCLK_USB3OTG_REF 96
+#define SCLK_USB3OTG_SUSPEND 97
+#define SCLK_REF_USB3OTG_SRC 98
+#define SCLK_MAC2IO_SRC 99
+
+/* dclk gates */
+#define DCLK_LCDC 180
+#define DCLK_HDMIPHY 181
+#define HDMIPHY 182
+#define USB480M 183
+#define DCLK_LCDC_SRC 184
+
+/* aclk gates */
+#define ACLK_AXISRAM 190
+#define ACLK_VOP_PRE 191
+#define ACLK_USB3OTG 192
+#define ACLK_RGA_PRE 193
+#define ACLK_DMAC 194
+#define ACLK_GPU 195
+#define ACLK_BUS_PRE 196
+#define ACLK_PERI_PRE 197
+#define ACLK_RKVDEC_PRE 198
+#define ACLK_RKVDEC 199
+#define ACLK_RKVENC 200
+#define ACLK_VPU_PRE 201
+#define ACLK_VIO_PRE 202
+#define ACLK_VPU 203
+#define ACLK_VIO 204
+#define ACLK_VOP 205
+#define ACLK_GMAC 206
+#define ACLK_H265 207
+#define ACLK_H264 208
+#define ACLK_MAC2PHY 209
+#define ACLK_MAC2IO 210
+#define ACLK_DCF 211
+#define ACLK_TSP 212
+#define ACLK_PERI 213
+#define ACLK_RGA 214
+#define ACLK_IEP 215
+#define ACLK_CIF 216
+#define ACLK_HDCP 217
+
+/* pclk gates */
+#define PCLK_GPIO0 300
+#define PCLK_GPIO1 301
+#define PCLK_GPIO2 302
+#define PCLK_GPIO3 303
+#define PCLK_GRF 304
+#define PCLK_I2C0 305
+#define PCLK_I2C1 306
+#define PCLK_I2C2 307
+#define PCLK_I2C3 308
+#define PCLK_SPI 309
+#define PCLK_UART0 310
+#define PCLK_UART1 311
+#define PCLK_UART2 312
+#define PCLK_TSADC 313
+#define PCLK_PWM 314
+#define PCLK_TIMER 315
+#define PCLK_BUS_PRE 316
+#define PCLK_PERI_PRE 317
+#define PCLK_HDMI_CTRL 318
+#define PCLK_HDMI_PHY 319
+#define PCLK_GMAC 320
+#define PCLK_H265 321
+#define PCLK_MAC2PHY 322
+#define PCLK_MAC2IO 323
+#define PCLK_USB3PHY_OTG 324
+#define PCLK_USB3PHY_PIPE 325
+#define PCLK_USB3_GRF 326
+#define PCLK_USB2_GRF 327
+#define PCLK_HDMIPHY 328
+#define PCLK_DDR 329
+#define PCLK_PERI 330
+#define PCLK_HDMI 331
+#define PCLK_HDCP 332
+#define PCLK_DCF 333
+#define PCLK_SARADC 334
+
+/* hclk gates */
+#define HCLK_PERI 408
+#define HCLK_TSP 409
+#define HCLK_GMAC 410
+#define HCLK_I2S0_8CH 411
+#define HCLK_I2S1_8CH 413
+#define HCLK_I2S2_2CH 413
+#define HCLK_SPDIF_8CH 414
+#define HCLK_VOP 415
+#define HCLK_NANDC 416
+#define HCLK_SDMMC 417
+#define HCLK_SDIO 418
+#define HCLK_EMMC 419
+#define HCLK_SDMMC_EXT 420
+#define HCLK_RKVDEC_PRE 421
+#define HCLK_RKVDEC 422
+#define HCLK_RKVENC 423
+#define HCLK_VPU_PRE 424
+#define HCLK_VIO_PRE 425
+#define HCLK_VPU 426
+#define HCLK_VIO 427
+#define HCLK_BUS_PRE 428
+#define HCLK_PERI_PRE 429
+#define HCLK_H264 430
+#define HCLK_CIF 431
+#define HCLK_OTG_PMU 432
+#define HCLK_OTG 433
+#define HCLK_HOST0 434
+#define HCLK_HOST0_ARB 435
+#define HCLK_CRYPTO_MST 436
+#define HCLK_CRYPTO_SLV 437
+#define HCLK_PDM 438
+#define HCLK_IEP 439
+#define HCLK_RGA 440
+#define HCLK_HDCP 441
+
+#define CLK_NR_CLKS (HCLK_HDCP + 1)
+
+#define SCLK_MAC2IO 0
+#define SCLK_MAC2PHY 1
+
+#define CLKGRF_NR_CLKS (SCLK_MAC2PHY + 1)
+
+/* soft-reset indices */
+#define SRST_CORE0_PO 0
+#define SRST_CORE1_PO 1
+#define SRST_CORE2_PO 2
+#define SRST_CORE3_PO 3
+#define SRST_CORE0 4
+#define SRST_CORE1 5
+#define SRST_CORE2 6
+#define SRST_CORE3 7
+#define SRST_CORE0_DBG 8
+#define SRST_CORE1_DBG 9
+#define SRST_CORE2_DBG 10
+#define SRST_CORE3_DBG 11
+#define SRST_TOPDBG 12
+#define SRST_CORE_NIU 13
+#define SRST_STRC_A 14
+#define SRST_L2C 15
+
+#define SRST_A53_GIC 18
+#define SRST_DAP 19
+#define SRST_PMU_P 21
+#define SRST_EFUSE 22
+#define SRST_BUSSYS_H 23
+#define SRST_BUSSYS_P 24
+#define SRST_SPDIF 25
+#define SRST_INTMEM 26
+#define SRST_ROM 27
+#define SRST_GPIO0 28
+#define SRST_GPIO1 29
+#define SRST_GPIO2 30
+#define SRST_GPIO3 31
+
+#define SRST_I2S0 32
+#define SRST_I2S1 33
+#define SRST_I2S2 34
+#define SRST_I2S0_H 35
+#define SRST_I2S1_H 36
+#define SRST_I2S2_H 37
+#define SRST_UART0 38
+#define SRST_UART1 39
+#define SRST_UART2 40
+#define SRST_UART0_P 41
+#define SRST_UART1_P 42
+#define SRST_UART2_P 43
+#define SRST_I2C0 44
+#define SRST_I2C1 45
+#define SRST_I2C2 46
+#define SRST_I2C3 47
+
+#define SRST_I2C0_P 48
+#define SRST_I2C1_P 49
+#define SRST_I2C2_P 50
+#define SRST_I2C3_P 51
+#define SRST_EFUSE_SE_P 52
+#define SRST_EFUSE_NS_P 53
+#define SRST_PWM0 54
+#define SRST_PWM0_P 55
+#define SRST_DMA 56
+#define SRST_TSP_A 57
+#define SRST_TSP_H 58
+#define SRST_TSP 59
+#define SRST_TSP_HSADC 60
+#define SRST_DCF_A 61
+#define SRST_DCF_P 62
+
+#define SRST_SCR 64
+#define SRST_SPI 65
+#define SRST_TSADC 66
+#define SRST_TSADC_P 67
+#define SRST_CRYPTO 68
+#define SRST_SGRF 69
+#define SRST_GRF 70
+#define SRST_USB_GRF 71
+#define SRST_TIMER_6CH_P 72
+#define SRST_TIMER0 73
+#define SRST_TIMER1 74
+#define SRST_TIMER2 75
+#define SRST_TIMER3 76
+#define SRST_TIMER4 77
+#define SRST_TIMER5 78
+#define SRST_USB3GRF 79
+
+#define SRST_PHYNIU 80
+#define SRST_HDMIPHY 81
+#define SRST_VDAC 82
+#define SRST_ACODEC_p 83
+#define SRST_SARADC 85
+#define SRST_SARADC_P 86
+#define SRST_GRF_DDR 87
+#define SRST_DFIMON 88
+#define SRST_MSCH 89
+#define SRST_DDRMSCH 91
+#define SRST_DDRCTRL 92
+#define SRST_DDRCTRL_P 93
+#define SRST_DDRPHY 94
+#define SRST_DDRPHY_P 95
+
+#define SRST_GMAC_NIU_A 96
+#define SRST_GMAC_NIU_P 97
+#define SRST_GMAC2PHY_A 98
+#define SRST_GMAC2IO_A 99
+#define SRST_MACPHY 100
+#define SRST_OTP_PHY 101
+#define SRST_GPU_A 102
+#define SRST_GPU_NIU_A 103
+#define SRST_SDMMCEXT 104
+#define SRST_PERIPH_NIU_A 105
+#define SRST_PERIHP_NIU_H 106
+#define SRST_PERIHP_P 107
+#define SRST_PERIPHSYS_H 108
+#define SRST_MMC0 109
+#define SRST_SDIO 110
+#define SRST_EMMC 111
+
+#define SRST_USB2OTG_H 112
+#define SRST_USB2OTG 113
+#define SRST_USB2OTG_ADP 114
+#define SRST_USB2HOST_H 115
+#define SRST_USB2HOST_ARB 116
+#define SRST_USB2HOST_AUX 117
+#define SRST_USB2HOST_EHCIPHY 118
+#define SRST_USB2HOST_UTMI 119
+#define SRST_USB3OTG 120
+#define SRST_USBPOR 121
+#define SRST_USB2OTG_UTMI 122
+#define SRST_USB2HOST_PHY_UTMI 123
+#define SRST_USB3OTG_UTMI 124
+#define SRST_USB3PHY_U2 125
+#define SRST_USB3PHY_U3 126
+#define SRST_USB3PHY_PIPE 127
+
+#define SRST_VIO_A 128
+#define SRST_VIO_BUS_H 129
+#define SRST_VIO_H2P_H 130
+#define SRST_VIO_ARBI_H 131
+#define SRST_VOP_NIU_A 132
+#define SRST_VOP_A 133
+#define SRST_VOP_H 134
+#define SRST_VOP_D 135
+#define SRST_RGA 136
+#define SRST_RGA_NIU_A 137
+#define SRST_RGA_A 138
+#define SRST_RGA_H 139
+#define SRST_IEP_A 140
+#define SRST_IEP_H 141
+#define SRST_HDMI 142
+#define SRST_HDMI_P 143
+
+#define SRST_HDCP_A 144
+#define SRST_HDCP 145
+#define SRST_HDCP_H 146
+#define SRST_CIF_A 147
+#define SRST_CIF_H 148
+#define SRST_CIF_P 149
+#define SRST_OTP_P 150
+#define SRST_OTP_SBPI 151
+#define SRST_OTP_USER 152
+#define SRST_DDRCTRL_A 153
+#define SRST_DDRSTDY_P 154
+#define SRST_DDRSTDY 155
+#define SRST_PDM_H 156
+#define SRST_PDM 157
+#define SRST_USB3PHY_OTG_P 158
+#define SRST_USB3PHY_PIPE_P 159
+
+#define SRST_VCODEC_A 160
+#define SRST_VCODEC_NIU_A 161
+#define SRST_VCODEC_H 162
+#define SRST_VCODEC_NIU_H 163
+#define SRST_VDEC_A 164
+#define SRST_VDEC_NIU_A 165
+#define SRST_VDEC_H 166
+#define SRST_VDEC_NIU_H 167
+#define SRST_VDEC_CORE 168
+#define SRST_VDEC_CABAC 169
+#define SRST_DDRPHYDIV 175
+
+#define SRST_RKVENC_NIU_A 176
+#define SRST_RKVENC_NIU_H 177
+#define SRST_RKVENC_H265_A 178
+#define SRST_RKVENC_H265_P 179
+#define SRST_RKVENC_H265_CORE 180
+#define SRST_RKVENC_H265_DSP 181
+#define SRST_RKVENC_H264_A 182
+#define SRST_RKVENC_H264_H 183
+#define SRST_RKVENC_INTMEM 184
+
+#endif
--
1.9.1
^ permalink raw reply related
* [PATCH v2 2/4] dt-bindings: add bindings for rk3328 clock controller
From: Elaine Zhang @ 2016-12-19 1:56 UTC (permalink / raw)
To: heiko-4mtYJXux2i+zQB+pC5nmwQ, mturquette-rdvid1DuHRBWk0Htik3J/w,
sboyd-sgV2jX0FEOL9JmXXK+q4OQ, xf-TNX95d0MmH7DzftRWevZcw
Cc: mark.rutland-5wv7dgnIgG8, devicetree-u79uwXL29TY76Z2rM5mHXA,
huangtao-TNX95d0MmH7DzftRWevZcw, xxx-TNX95d0MmH7DzftRWevZcw,
Elaine Zhang, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, cl-TNX95d0MmH7DzftRWevZcw,
linux-clk-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <1482112573-11613-1-git-send-email-zhangqing-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
Add devicetree bindings for Rockchip cru which found on
Rockchip SoCs.
Signed-off-by: Elaine Zhang <zhangqing-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
---
.../bindings/clock/rockchip,rk3328-cru.txt | 57 ++++++++++++++++++++++
1 file changed, 57 insertions(+)
create mode 100644 Documentation/devicetree/bindings/clock/rockchip,rk3328-cru.txt
diff --git a/Documentation/devicetree/bindings/clock/rockchip,rk3328-cru.txt b/Documentation/devicetree/bindings/clock/rockchip,rk3328-cru.txt
new file mode 100644
index 000000000000..20053494d49f
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/rockchip,rk3328-cru.txt
@@ -0,0 +1,57 @@
+* Rockchip RK3328 Clock and Reset Unit
+
+The RK3328 clock controller generates and supplies clock to various
+controllers within the SoC and also implements a reset controller for SoC
+peripherals.
+
+Required Properties:
+
+- compatible: should be "rockchip,rk3328-cru"
+- reg: physical base address of the controller and length of memory mapped
+ region.
+- #clock-cells: should be 1.
+- #reset-cells: should be 1.
+
+Optional Properties:
+
+- rockchip,grf: phandle to the syscon managing the "general register files"
+ If missing pll rates are not changeable, due to the missing pll lock status.
+
+Each clock is assigned an identifier and client nodes can use this identifier
+to specify the clock which they consume. All available clocks are defined as
+preprocessor macros in the dt-bindings/clock/rk3328-cru.h headers and can be
+used in device tree sources. Similar macros exist for the reset sources in
+these files.
+
+External clocks:
+
+There are several clocks that are generated outside the SoC. It is expected
+that they are defined using standard clock bindings with following
+clock-output-names:
+ - "xin24m" - crystal input - required,
+ - "clkin_i2s" - external I2S clock - optional,
+ - "gmac_clkin" - external GMAC clock - optional
+ - "phy_50m_out" - output clock of the pll in the mac phy
+
+Example: Clock controller node:
+
+ cru: clock-controller@ff440000 {
+ compatible = "rockchip,rk3328-cru", "rockchip,cru", "syscon";
+ reg = <0x0 0xff440000 0x0 0x1000>;
+ rockchip,grf = <&grf>;
+
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
+Example: UART controller node that consumes the clock generated by the clock
+ controller:
+
+ uart0: serial@ff120000 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0xff120000 0x100>;
+ interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ clocks = <&cru SCLK_UART0>;
+ };
--
1.9.1
^ permalink raw reply related
* [PATCH v2 3/4] clk: rockchip: add clock controller for rk3328
From: Elaine Zhang @ 2016-12-19 1:56 UTC (permalink / raw)
To: heiko, mturquette, sboyd, xf
Cc: robh+dt, mark.rutland, linux-clk, linux-arm-kernel, devicetree,
huangtao, xxx, cl, linux-rockchip, linux-kernel, Elaine Zhang
In-Reply-To: <1482112573-11613-1-git-send-email-zhangqing@rock-chips.com>
Add the clock tree definition for the new rk3328 SoC.
Changes in v2:
fix up these *_sample error description.
Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
---
drivers/clk/rockchip/Makefile | 1 +
drivers/clk/rockchip/clk-rk3328.c | 1068 +++++++++++++++++++++++++++++++++++++
drivers/clk/rockchip/clk.h | 23 +
3 files changed, 1092 insertions(+)
create mode 100644 drivers/clk/rockchip/clk-rk3328.c
diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile
index 16e098c36f90..68b04bfca282 100644
--- a/drivers/clk/rockchip/Makefile
+++ b/drivers/clk/rockchip/Makefile
@@ -16,5 +16,6 @@ obj-y += clk-rk3036.o
obj-y += clk-rk3188.o
obj-y += clk-rk3228.o
obj-y += clk-rk3288.o
+obj-y += clk-rk3328.o
obj-y += clk-rk3368.o
obj-y += clk-rk3399.o
diff --git a/drivers/clk/rockchip/clk-rk3328.c b/drivers/clk/rockchip/clk-rk3328.c
new file mode 100644
index 000000000000..d283796ec2f0
--- /dev/null
+++ b/drivers/clk/rockchip/clk-rk3328.c
@@ -0,0 +1,1068 @@
+/*
+ * Copyright (c) 2016 Rockchip Electronics Co. Ltd.
+ * Author: Elaine <zhangqing@rock-chips.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that 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.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/syscore_ops.h>
+#include <dt-bindings/clock/rk3328-cru.h>
+#include "clk.h"
+
+#define RK3328_GRF_SOC_STATUS0 0x480
+#define RK3328_GRF_MAC_CON1 0x904
+#define RK3328_GRF_MAC_CON2 0x908
+
+enum rk3328_plls {
+ apll, dpll, cpll, gpll, npll,
+};
+
+static struct rockchip_pll_rate_table rk3328_pll_rates[] = {
+ /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */
+ RK3036_PLL_RATE(1608000000, 1, 67, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1584000000, 1, 66, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1560000000, 1, 65, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1536000000, 1, 64, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1512000000, 1, 63, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1488000000, 1, 62, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1464000000, 1, 61, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1440000000, 1, 60, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1416000000, 1, 59, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1392000000, 1, 58, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1368000000, 1, 57, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1344000000, 1, 56, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1320000000, 1, 55, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1296000000, 1, 54, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1272000000, 1, 53, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1248000000, 1, 52, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1188000000, 2, 99, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1104000000, 1, 46, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1100000000, 12, 550, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1008000000, 1, 84, 2, 1, 1, 0),
+ RK3036_PLL_RATE(1000000000, 6, 500, 2, 1, 1, 0),
+ RK3036_PLL_RATE(984000000, 1, 82, 2, 1, 1, 0),
+ RK3036_PLL_RATE(960000000, 1, 80, 2, 1, 1, 0),
+ RK3036_PLL_RATE(936000000, 1, 78, 2, 1, 1, 0),
+ RK3036_PLL_RATE(912000000, 1, 76, 2, 1, 1, 0),
+ RK3036_PLL_RATE(900000000, 4, 300, 2, 1, 1, 0),
+ RK3036_PLL_RATE(888000000, 1, 74, 2, 1, 1, 0),
+ RK3036_PLL_RATE(864000000, 1, 72, 2, 1, 1, 0),
+ RK3036_PLL_RATE(840000000, 1, 70, 2, 1, 1, 0),
+ RK3036_PLL_RATE(816000000, 1, 68, 2, 1, 1, 0),
+ RK3036_PLL_RATE(800000000, 6, 400, 2, 1, 1, 0),
+ RK3036_PLL_RATE(700000000, 6, 350, 2, 1, 1, 0),
+ RK3036_PLL_RATE(696000000, 1, 58, 2, 1, 1, 0),
+ RK3036_PLL_RATE(600000000, 1, 75, 3, 1, 1, 0),
+ RK3036_PLL_RATE(594000000, 2, 99, 2, 1, 1, 0),
+ RK3036_PLL_RATE(504000000, 1, 63, 3, 1, 1, 0),
+ RK3036_PLL_RATE(500000000, 6, 250, 2, 1, 1, 0),
+ RK3036_PLL_RATE(408000000, 1, 68, 2, 2, 1, 0),
+ RK3036_PLL_RATE(312000000, 1, 52, 2, 2, 1, 0),
+ RK3036_PLL_RATE(216000000, 1, 72, 4, 2, 1, 0),
+ RK3036_PLL_RATE(96000000, 1, 64, 4, 4, 1, 0),
+ { /* sentinel */ },
+};
+
+static struct rockchip_pll_rate_table rk3328_pll_frac_rates[] = {
+ /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */
+ RK3036_PLL_RATE(1016064000, 3, 127, 1, 1, 0, 134217),
+ /* vco = 1016064000 */
+ RK3036_PLL_RATE(983040000, 24, 983, 1, 1, 0, 671088),
+ /* vco = 983040000 */
+ RK3036_PLL_RATE(491520000, 24, 983, 2, 1, 0, 671088),
+ /* vco = 983040000 */
+ RK3036_PLL_RATE(61440000, 6, 215, 7, 2, 0, 671088),
+ /* vco = 860156000 */
+ RK3036_PLL_RATE(56448000, 12, 451, 4, 4, 0, 9797894),
+ /* vco = 903168000 */
+ RK3036_PLL_RATE(40960000, 12, 409, 4, 5, 0, 10066329),
+ /* vco = 819200000 */
+ { /* sentinel */ },
+};
+
+#define RK3328_DIV_CPU_MASK 0x1f
+#define RK3328_DIV_CPU_SHIFT 8
+
+#define RK3328_DIV_PERI_MASK 0xf
+#define RK3328_DIV_PERI_SHIFT 0
+#define RK3328_DIV_ACLK_MASK 0x7
+#define RK3328_DIV_ACLK_SHIFT 4
+#define RK3328_DIV_HCLK_MASK 0x3
+#define RK3328_DIV_HCLK_SHIFT 8
+#define RK3328_DIV_PCLK_MASK 0x7
+#define RK3328_DIV_PCLK_SHIFT 12
+
+#define RK3328_CLKSEL1(_aclk_core, _pclk_dbg) \
+{ \
+ .reg = RK3328_CLKSEL_CON(1), \
+ .val = HIWORD_UPDATE(_aclk_core, RK3328_DIV_ACLKM_MASK, \
+ RK3328_DIV_ACLKM_SHIFT) | \
+ HIWORD_UPDATE(_pclk_dbg, RK3328_DIV_PCLK_DBG_MASK, \
+ RK3328_DIV_PCLK_DBG_SHIFT), \
+}
+
+#define RK3328_CPUCLK_RATE(_prate, _aclk_core, _pclk_dbg) \
+{ \
+ .prate = _prate, \
+ .divs = { \
+ RK3328_CLKSEL1(_aclk_core, _pclk_dbg), \
+ }, \
+}
+
+static struct rockchip_cpuclk_rate_table rk3328_cpuclk_rates[] __initdata = {
+ RK3328_CPUCLK_RATE(1800000000, 1, 7),
+ RK3328_CPUCLK_RATE(1704000000, 1, 7),
+ RK3328_CPUCLK_RATE(1608000000, 1, 7),
+ RK3328_CPUCLK_RATE(1512000000, 1, 7),
+ RK3328_CPUCLK_RATE(1488000000, 1, 5),
+ RK3328_CPUCLK_RATE(1416000000, 1, 5),
+ RK3328_CPUCLK_RATE(1392000000, 1, 5),
+ RK3328_CPUCLK_RATE(1296000000, 1, 5),
+ RK3328_CPUCLK_RATE(1200000000, 1, 5),
+ RK3328_CPUCLK_RATE(1104000000, 1, 5),
+ RK3328_CPUCLK_RATE(1008000000, 1, 5),
+ RK3328_CPUCLK_RATE(912000000, 1, 5),
+ RK3328_CPUCLK_RATE(816000000, 1, 3),
+ RK3328_CPUCLK_RATE(696000000, 1, 3),
+ RK3328_CPUCLK_RATE(600000000, 1, 3),
+ RK3328_CPUCLK_RATE(408000000, 1, 1),
+ RK3328_CPUCLK_RATE(312000000, 1, 1),
+ RK3328_CPUCLK_RATE(216000000, 1, 1),
+ RK3328_CPUCLK_RATE(96000000, 1, 1),
+};
+
+static const struct rockchip_cpuclk_reg_data rk3328_cpuclk_data = {
+ .core_reg = RK3328_CLKSEL_CON(0),
+ .div_core_shift = 0,
+ .div_core_mask = 0x1f,
+ .mux_core_alt = 1,
+ .mux_core_main = 3,
+ .mux_core_shift = 6,
+ .mux_core_mask = 0x3,
+};
+
+PNAME(mux_pll_p) = { "xin24m", "xin24m" };
+
+PNAME(mux_2plls_p) = { "cpll", "gpll" };
+PNAME(mux_gpll_cpll_p) = { "gpll", "cpll" };
+PNAME(mux_cpll_gpll_apll_p) = { "cpll", "gpll", "apll" };
+PNAME(mux_2plls_xin24m_p) = { "cpll", "gpll", "xin24m" };
+PNAME(mux_2plls_hdmiphy_p) = { "cpll", "gpll",
+ "dummy_hdmiphy" };
+PNAME(mux_4plls_p) = { "cpll", "gpll",
+ "dummy_hdmiphy",
+ "usb480m" };
+PNAME(mux_2plls_u480m_p) = { "cpll", "gpll",
+ "usb480m" };
+PNAME(mux_2plls_24m_u480m_p) = { "cpll", "gpll",
+ "xin24m", "usb480m" };
+
+PNAME(mux_ddrphy_p) = { "dpll", "apll", "cpll" };
+PNAME(mux_armclk_p) = { "apll_core",
+ "gpll_core",
+ "dpll_core",
+ "npll_core"};
+PNAME(mux_hdmiphy_p) = { "hdmi_phy", "xin24m" };
+PNAME(mux_usb480m_p) = { "usb480m_phy",
+ "xin24m" };
+
+PNAME(mux_i2s0_p) = { "clk_i2s0_div",
+ "clk_i2s0_frac",
+ "xin12m",
+ "xin12m" };
+PNAME(mux_i2s1_p) = { "clk_i2s1_div",
+ "clk_i2s1_frac",
+ "clkin_i2s1",
+ "xin12m" };
+PNAME(mux_i2s2_p) = { "clk_i2s2_div",
+ "clk_i2s2_frac",
+ "clkin_i2s2",
+ "xin12m" };
+PNAME(mux_i2s1out_p) = { "clk_i2s1", "xin12m"};
+PNAME(mux_i2s2out_p) = { "clk_i2s2", "xin12m" };
+PNAME(mux_spdif_p) = { "clk_spdif_div",
+ "clk_spdif_frac",
+ "xin12m",
+ "xin12m" };
+PNAME(mux_uart0_p) = { "clk_uart0_div",
+ "clk_uart0_frac",
+ "xin24m" };
+PNAME(mux_uart1_p) = { "clk_uart1_div",
+ "clk_uart1_frac",
+ "xin24m" };
+PNAME(mux_uart2_p) = { "clk_uart2_div",
+ "clk_uart2_frac",
+ "xin24m" };
+
+PNAME(mux_sclk_cif_p) = { "clk_cif_src",
+ "xin24m" };
+PNAME(mux_dclk_lcdc_p) = { "hdmiphy",
+ "dclk_lcdc_src" };
+PNAME(mux_aclk_peri_pre_p) = { "cpll_peri",
+ "gpll_peri",
+ "hdmiphy_peri" };
+PNAME(mux_ref_usb3otg_src_p) = { "xin24m",
+ "clk_usb3otg_ref" };
+PNAME(mux_xin24m_32k_p) = { "xin24m",
+ "clk_rtc32k" };
+PNAME(mux_mac2io_src_p) = { "clk_mac2io_src",
+ "gmac_clkin" };
+PNAME(mux_mac2phy_src_p) = { "clk_mac2phy_src",
+ "phy_50m_out" };
+
+static struct rockchip_pll_clock rk3328_pll_clks[] __initdata = {
+ [apll] = PLL(pll_rk3328, PLL_APLL, "apll", mux_pll_p,
+ 0, RK3328_PLL_CON(0),
+ RK3328_MODE_CON, 0, 4, 0, rk3328_pll_frac_rates),
+ [dpll] = PLL(pll_rk3328, PLL_DPLL, "dpll", mux_pll_p,
+ 0, RK3328_PLL_CON(8),
+ RK3328_MODE_CON, 4, 3, 0, NULL),
+ [cpll] = PLL(pll_rk3328, PLL_CPLL, "cpll", mux_pll_p,
+ 0, RK3328_PLL_CON(16),
+ RK3328_MODE_CON, 8, 2, 0, rk3328_pll_rates),
+ [gpll] = PLL(pll_rk3328, PLL_GPLL, "gpll", mux_pll_p,
+ 0, RK3328_PLL_CON(24),
+ RK3328_MODE_CON, 12, 1, 0, rk3328_pll_frac_rates),
+ [npll] = PLL(pll_rk3328, PLL_NPLL, "npll", mux_pll_p,
+ 0, RK3328_PLL_CON(40),
+ RK3328_MODE_CON, 1, 0, 0, rk3328_pll_rates),
+};
+
+#define MFLAGS CLK_MUX_HIWORD_MASK
+#define DFLAGS CLK_DIVIDER_HIWORD_MASK
+#define GFLAGS (CLK_GATE_HIWORD_MASK | CLK_GATE_SET_TO_DISABLE)
+
+static struct rockchip_clk_branch rk3328_i2s0_fracmux __initdata =
+ MUX(0, "i2s0_pre", mux_i2s0_p, CLK_SET_RATE_PARENT,
+ RK3328_CLKSEL_CON(6), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3328_i2s1_fracmux __initdata =
+ MUX(0, "i2s1_pre", mux_i2s1_p, CLK_SET_RATE_PARENT,
+ RK3328_CLKSEL_CON(8), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3328_i2s2_fracmux __initdata =
+ MUX(0, "i2s2_pre", mux_i2s2_p, CLK_SET_RATE_PARENT,
+ RK3328_CLKSEL_CON(10), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3328_spdif_fracmux __initdata =
+ MUX(SCLK_SPDIF, "sclk_spdif", mux_spdif_p, CLK_SET_RATE_PARENT,
+ RK3328_CLKSEL_CON(12), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3328_uart0_fracmux __initdata =
+ MUX(SCLK_UART0, "sclk_uart0", mux_uart0_p, CLK_SET_RATE_PARENT,
+ RK3328_CLKSEL_CON(14), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3328_uart1_fracmux __initdata =
+ MUX(SCLK_UART1, "sclk_uart1", mux_uart1_p, CLK_SET_RATE_PARENT,
+ RK3328_CLKSEL_CON(16), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3328_uart2_fracmux __initdata =
+ MUX(SCLK_UART2, "sclk_uart2", mux_uart2_p, CLK_SET_RATE_PARENT,
+ RK3328_CLKSEL_CON(18), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
+ /*
+ * Clock-Architecture Diagram 1
+ */
+
+ DIV(0, "clk_24m", "xin24m", CLK_IGNORE_UNUSED,
+ RK3328_CLKSEL_CON(2), 8, 5, DFLAGS),
+ COMPOSITE(SCLK_RTC32K, "clk_rtc32k", mux_2plls_xin24m_p, 0,
+ RK3328_CLKSEL_CON(38), 14, 2, MFLAGS, 0, 14, DFLAGS,
+ RK3328_CLKGATE_CON(0), 11, GFLAGS),
+ /* PD_MISC */
+ MUX(HDMIPHY, "hdmiphy", mux_hdmiphy_p, CLK_SET_RATE_PARENT,
+ RK3328_MISC_CON, 13, 1, MFLAGS),
+ MUX(USB480M, "usb480m", mux_usb480m_p, CLK_SET_RATE_PARENT,
+ RK3328_MISC_CON, 15, 1, MFLAGS),
+
+ /*
+ * Clock-Architecture Diagram 2
+ */
+
+ /* PD_CORE */
+ GATE(0, "apll_core", "apll", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(0), 0, GFLAGS),
+ GATE(0, "gpll_core", "gpll", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(0), 2, GFLAGS),
+ GATE(0, "dpll_core", "dpll", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(0), 1, GFLAGS),
+ GATE(0, "npll_core", "npll", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(0), 12, GFLAGS),
+ COMPOSITE_NOMUX(0, "pclk_dbg", "armclk", CLK_IGNORE_UNUSED,
+ RK3328_CLKSEL_CON(1), 0, 4,
+ DFLAGS | CLK_DIVIDER_READ_ONLY,
+ RK3328_CLKGATE_CON(7), 0, GFLAGS),
+ COMPOSITE_NOMUX(0, "aclk_core", "armclk", CLK_IGNORE_UNUSED,
+ RK3328_CLKSEL_CON(1), 4, 3,
+ DFLAGS | CLK_DIVIDER_READ_ONLY,
+ RK3328_CLKGATE_CON(7), 1, GFLAGS),
+ GATE(0, "aclk_core_niu", "aclk_core", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(13), 0, GFLAGS),
+ GATE(0, "aclk_gic400", "aclk_core", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(13), 1, GFLAGS),
+
+ GATE(0, "clk_jtag", "jtag_clkin", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(7), 2, GFLAGS),
+
+ /* PD_GPU */
+ COMPOSITE(0, "aclk_gpu_pre", mux_4plls_p, 0,
+ RK3328_CLKSEL_CON(44), 6, 2, MFLAGS, 0, 5, DFLAGS,
+ RK3328_CLKGATE_CON(6), 6, GFLAGS),
+ GATE(ACLK_GPU, "aclk_gpu", "aclk_gpu_pre", CLK_SET_RATE_PARENT,
+ RK3328_CLKGATE_CON(14), 0, GFLAGS),
+ GATE(0, "aclk_gpu_niu", "aclk_gpu_pre", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(14), 1, GFLAGS),
+
+ /* PD_DDR */
+ COMPOSITE(0, "clk_ddr", mux_ddrphy_p, CLK_IGNORE_UNUSED,
+ RK3328_CLKSEL_CON(3), 8, 2, MFLAGS, 0, 3,
+ DFLAGS | CLK_DIVIDER_POWER_OF_TWO,
+ RK3328_CLKGATE_CON(0), 4, GFLAGS),
+ GATE(0, "clk_ddrmsch", "clk_ddr", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(18), 6, GFLAGS),
+ GATE(0, "clk_ddrupctl", "clk_ddr", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(18), 5, GFLAGS),
+ GATE(0, "aclk_ddrupctl", "clk_ddr", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(18), 4, GFLAGS),
+ GATE(0, "clk_ddrmon", "xin24m", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(0), 6, GFLAGS),
+
+ COMPOSITE(PCLK_DDR, "pclk_ddr", mux_2plls_hdmiphy_p, 0,
+ RK3328_CLKSEL_CON(4), 13, 2, MFLAGS, 8, 3, DFLAGS,
+ RK3328_CLKGATE_CON(7), 4, GFLAGS),
+ GATE(0, "pclk_ddrupctl", "pclk_ddr", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(18), 1, GFLAGS),
+ GATE(0, "pclk_ddr_msch", "pclk_ddr", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(18), 2, GFLAGS),
+ GATE(0, "pclk_ddr_mon", "pclk_ddr", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(18), 3, GFLAGS),
+ GATE(0, "pclk_ddrstdby", "pclk_ddr", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(18), 7, GFLAGS),
+ GATE(0, "pclk_ddr_grf", "pclk_ddr", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(18), 9, GFLAGS),
+
+ /*
+ * Clock-Architecture Diagram 3
+ */
+ /* PD_BUS */
+ COMPOSITE(ACLK_BUS_PRE, "aclk_bus_pre", mux_2plls_hdmiphy_p, 0,
+ RK3328_CLKSEL_CON(0), 13, 2, MFLAGS, 8, 5, DFLAGS,
+ RK3328_CLKGATE_CON(8), 0, GFLAGS),
+ COMPOSITE_NOMUX(HCLK_BUS_PRE, "hclk_bus_pre", "aclk_bus_pre", 0,
+ RK3328_CLKSEL_CON(1), 8, 2, DFLAGS,
+ RK3328_CLKGATE_CON(8), 1, GFLAGS),
+ COMPOSITE_NOMUX(PCLK_BUS_PRE, "pclk_bus_pre", "aclk_bus_pre", 0,
+ RK3328_CLKSEL_CON(1), 12, 3, DFLAGS,
+ RK3328_CLKGATE_CON(8), 2, GFLAGS),
+ GATE(0, "pclk_bus", "pclk_bus_pre", 0,
+ RK3328_CLKGATE_CON(8), 3, GFLAGS),
+ GATE(0, "pclk_phy_pre", "pclk_bus_pre", 0,
+ RK3328_CLKGATE_CON(8), 4, GFLAGS),
+
+ COMPOSITE(SCLK_TSP, "clk_tsp", mux_2plls_p, 0,
+ RK3328_CLKSEL_CON(21), 15, 1, MFLAGS, 8, 5, DFLAGS,
+ RK3328_CLKGATE_CON(2), 5, GFLAGS),
+ GATE(0, "clk_hsadc_tsp", "ext_gpio3a2", 0,
+ RK3328_CLKGATE_CON(17), 13, GFLAGS),
+
+ /* PD_I2S */
+ COMPOSITE(0, "clk_i2s0_div", mux_2plls_p, 0,
+ RK3328_CLKSEL_CON(6), 15, 1, MFLAGS, 0, 7, DFLAGS,
+ RK3328_CLKGATE_CON(1), 1, GFLAGS),
+ COMPOSITE_FRACMUX(0, "clk_i2s0_frac", "clk_i2s0_div",
+ CLK_SET_RATE_PARENT,
+ RK3328_CLKSEL_CON(7), 0,
+ RK3328_CLKGATE_CON(1), 2, GFLAGS,
+ &rk3328_i2s0_fracmux),
+ GATE(SCLK_I2S0, "clk_i2s0", "i2s0_pre", CLK_SET_RATE_PARENT,
+ RK3328_CLKGATE_CON(1), 3, GFLAGS),
+
+ COMPOSITE(0, "clk_i2s1_div", mux_2plls_p, 0,
+ RK3328_CLKSEL_CON(8), 15, 1, MFLAGS, 0, 7, DFLAGS,
+ RK3328_CLKGATE_CON(1), 4, GFLAGS),
+ COMPOSITE_FRACMUX(0, "clk_i2s1_frac", "clk_i2s1_div",
+ CLK_SET_RATE_PARENT,
+ RK3328_CLKSEL_CON(9), 0,
+ RK3328_CLKGATE_CON(1), 5, GFLAGS,
+ &rk3328_i2s1_fracmux),
+ GATE(SCLK_I2S1, "clk_i2s1", "i2s1_pre", CLK_SET_RATE_PARENT,
+ RK3328_CLKGATE_CON(0), 6, GFLAGS),
+ COMPOSITE_NODIV(SCLK_I2S1_OUT, "i2s1_out", mux_i2s1out_p, 0,
+ RK3328_CLKSEL_CON(8), 12, 1, MFLAGS,
+ RK3328_CLKGATE_CON(1), 7, GFLAGS),
+
+ COMPOSITE(0, "clk_i2s2_div", mux_2plls_p, 0,
+ RK3328_CLKSEL_CON(10), 15, 1, MFLAGS, 0, 7, DFLAGS,
+ RK3328_CLKGATE_CON(1), 8, GFLAGS),
+ COMPOSITE_FRACMUX(0, "clk_i2s2_frac", "clk_i2s2_div",
+ CLK_SET_RATE_PARENT,
+ RK3328_CLKSEL_CON(11), 0,
+ RK3328_CLKGATE_CON(1), 9, GFLAGS,
+ &rk3328_i2s2_fracmux),
+ GATE(SCLK_I2S2, "clk_i2s2", "i2s2_pre", CLK_SET_RATE_PARENT,
+ RK3328_CLKGATE_CON(1), 10, GFLAGS),
+ COMPOSITE_NODIV(SCLK_I2S2_OUT, "i2s2_out", mux_i2s2out_p, 0,
+ RK3328_CLKSEL_CON(10), 12, 1, MFLAGS,
+ RK3328_CLKGATE_CON(1), 11, GFLAGS),
+
+ COMPOSITE(0, "clk_spdif_div", mux_2plls_p, 0,
+ RK3328_CLKSEL_CON(12), 15, 1, MFLAGS, 0, 7, DFLAGS,
+ RK3328_CLKGATE_CON(1), 12, GFLAGS),
+ COMPOSITE_FRACMUX(0, "clk_spdif_frac", "clk_spdif_div",
+ CLK_SET_RATE_PARENT,
+ RK3328_CLKSEL_CON(13), 0,
+ RK3328_CLKGATE_CON(1), 13, GFLAGS,
+ &rk3328_spdif_fracmux),
+
+ /* PD_UART */
+ COMPOSITE(0, "clk_uart0_div", mux_2plls_u480m_p, 0,
+ RK3328_CLKSEL_CON(14), 12, 2, MFLAGS, 0, 7, DFLAGS,
+ RK3328_CLKGATE_CON(1), 14, GFLAGS),
+ COMPOSITE(0, "clk_uart1_div", mux_2plls_u480m_p, 0,
+ RK3328_CLKSEL_CON(16), 12, 2, MFLAGS, 0, 7, DFLAGS,
+ RK3328_CLKGATE_CON(2), 0, GFLAGS),
+ COMPOSITE(0, "clk_uart2_div", mux_2plls_u480m_p,
+ 0, RK3328_CLKSEL_CON(18), 12, 2, MFLAGS, 0, 7, DFLAGS,
+ RK3328_CLKGATE_CON(2), 2, GFLAGS),
+ COMPOSITE_FRACMUX(0, "clk_uart0_frac", "clk_uart0_div",
+ CLK_SET_RATE_PARENT,
+ RK3328_CLKSEL_CON(15), 0,
+ RK3328_CLKGATE_CON(1), 15, GFLAGS,
+ &rk3328_uart0_fracmux),
+ COMPOSITE_FRACMUX(0, "clk_uart1_frac", "clk_uart1_div",
+ CLK_SET_RATE_PARENT,
+ RK3328_CLKSEL_CON(17), 0,
+ RK3328_CLKGATE_CON(2), 1, GFLAGS,
+ &rk3328_uart1_fracmux),
+ COMPOSITE_FRACMUX(0, "clk_uart2_frac", "clk_uart2_div",
+ CLK_SET_RATE_PARENT,
+ RK3328_CLKSEL_CON(19), 0,
+ RK3328_CLKGATE_CON(2), 3, GFLAGS,
+ &rk3328_uart2_fracmux),
+
+ /*
+ * Clock-Architecture Diagram 4
+ */
+ COMPOSITE(SCLK_I2C0, "clk_i2c0", mux_2plls_p, 0,
+ RK3328_CLKSEL_CON(34), 7, 1, MFLAGS, 0, 7, DFLAGS,
+ RK3328_CLKGATE_CON(2), 9, GFLAGS),
+ COMPOSITE(SCLK_I2C1, "clk_i2c1", mux_2plls_p, 0,
+ RK3328_CLKSEL_CON(34), 15, 1, MFLAGS, 8, 7, DFLAGS,
+ RK3328_CLKGATE_CON(2), 10, GFLAGS),
+ COMPOSITE(SCLK_I2C2, "clk_i2c2", mux_2plls_p, 0,
+ RK3328_CLKSEL_CON(35), 7, 1, MFLAGS, 0, 7, DFLAGS,
+ RK3328_CLKGATE_CON(2), 11, GFLAGS),
+ COMPOSITE(SCLK_I2C3, "clk_i2c3", mux_2plls_p, 0,
+ RK3328_CLKSEL_CON(35), 15, 1, MFLAGS, 8, 7, DFLAGS,
+ RK3328_CLKGATE_CON(2), 12, GFLAGS),
+ COMPOSITE(SCLK_CRYPTO, "clk_crypto", mux_2plls_p, 0,
+ RK3328_CLKSEL_CON(20), 7, 1, MFLAGS, 0, 7, DFLAGS,
+ RK3328_CLKGATE_CON(2), 4, GFLAGS),
+ COMPOSITE_NOMUX(SCLK_TSADC, "clk_tsadc", "clk_24m", 0,
+ RK3328_CLKSEL_CON(22), 0, 10, DFLAGS,
+ RK3328_CLKGATE_CON(2), 6, GFLAGS),
+ COMPOSITE_NOMUX(SCLK_SARADC, "clk_saradc", "clk_24m", 0,
+ RK3328_CLKSEL_CON(23), 0, 10, DFLAGS,
+ RK3328_CLKGATE_CON(2), 14, GFLAGS),
+ COMPOSITE(SCLK_SPI, "clk_spi", mux_2plls_p, 0,
+ RK3328_CLKSEL_CON(24), 7, 1, MFLAGS, 0, 7, DFLAGS,
+ RK3328_CLKGATE_CON(2), 7, GFLAGS),
+ COMPOSITE(SCLK_PWM, "clk_pwm", mux_2plls_p, 0,
+ RK3328_CLKSEL_CON(24), 15, 1, MFLAGS, 8, 7, DFLAGS,
+ RK3328_CLKGATE_CON(2), 8, GFLAGS),
+ COMPOSITE(SCLK_OTP, "clk_otp", mux_2plls_xin24m_p, 0,
+ RK3328_CLKSEL_CON(4), 6, 2, MFLAGS, 0, 6, DFLAGS,
+ RK3328_CLKGATE_CON(3), 8, GFLAGS),
+ COMPOSITE(SCLK_EFUSE, "clk_efuse", mux_2plls_xin24m_p, 0,
+ RK3328_CLKSEL_CON(5), 14, 2, MFLAGS, 8, 5, DFLAGS,
+ RK3328_CLKGATE_CON(2), 13, GFLAGS),
+ COMPOSITE(SCLK_PDM, "clk_pdm", mux_cpll_gpll_apll_p,
+ CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT,
+ RK3328_CLKSEL_CON(20), 14, 2, MFLAGS, 8, 5, DFLAGS,
+ RK3328_CLKGATE_CON(2), 15, GFLAGS),
+
+ GATE(SCLK_TIMER0, "sclk_timer0", "xin24m", 0,
+ RK3328_CLKGATE_CON(8), 5, GFLAGS),
+ GATE(SCLK_TIMER1, "sclk_timer1", "xin24m", 0,
+ RK3328_CLKGATE_CON(8), 6, GFLAGS),
+ GATE(SCLK_TIMER2, "sclk_timer2", "xin24m", 0,
+ RK3328_CLKGATE_CON(8), 7, GFLAGS),
+ GATE(SCLK_TIMER3, "sclk_timer3", "xin24m", 0,
+ RK3328_CLKGATE_CON(8), 8, GFLAGS),
+ GATE(SCLK_TIMER4, "sclk_timer4", "xin24m", 0,
+ RK3328_CLKGATE_CON(8), 9, GFLAGS),
+ GATE(SCLK_TIMER5, "sclk_timer5", "xin24m", 0,
+ RK3328_CLKGATE_CON(8), 10, GFLAGS),
+
+ COMPOSITE(SCLK_WIFI, "clk_wifi", mux_2plls_u480m_p, 0,
+ RK3328_CLKSEL_CON(52), 6, 2, MFLAGS, 0, 6, DFLAGS,
+ RK3328_CLKGATE_CON(0), 10, GFLAGS),
+
+ /*
+ * Clock-Architecture Diagram 5
+ */
+ /* PD_VIDEO */
+ COMPOSITE(ACLK_RKVDEC_PRE, "aclk_rkvdec_pre", mux_4plls_p, 0,
+ RK3328_CLKSEL_CON(48), 6, 2, MFLAGS, 0, 5, DFLAGS,
+ RK3328_CLKGATE_CON(6), 0, GFLAGS),
+ FACTOR_GATE(HCLK_RKVDEC_PRE, "hclk_rkvdec_pre", "aclk_rkvdec_pre",
+ 0, 1, 4,
+ RK3328_CLKGATE_CON(11), 0, GFLAGS),
+ GATE(ACLK_RKVDEC, "aclk_rkvdec", "aclk_rkvdec_pre", CLK_SET_RATE_PARENT,
+ RK3328_CLKGATE_CON(24), 0, GFLAGS),
+ GATE(HCLK_RKVDEC, "hclk_rkvdec", "hclk_rkvdec_pre", CLK_SET_RATE_PARENT,
+ RK3328_CLKGATE_CON(24), 1, GFLAGS),
+ GATE(0, "aclk_rkvdec_niu", "aclk_rkvdec_pre", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(24), 2, GFLAGS),
+ GATE(0, "hclk_rkvdec_niu", "hclk_rkvdec_pre", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(24), 3, GFLAGS),
+
+ COMPOSITE(SCLK_VDEC_CABAC, "sclk_vdec_cabac", mux_4plls_p, 0,
+ RK3328_CLKSEL_CON(48), 14, 2, MFLAGS, 8, 5, DFLAGS,
+ RK3328_CLKGATE_CON(6), 1, GFLAGS),
+
+ COMPOSITE(SCLK_VDEC_CORE, "sclk_vdec_core", mux_4plls_p, 0,
+ RK3328_CLKSEL_CON(49), 6, 2, MFLAGS, 0, 5, DFLAGS,
+ RK3328_CLKGATE_CON(6), 2, GFLAGS),
+
+ COMPOSITE(ACLK_VPU_PRE, "aclk_vpu_pre", mux_4plls_p, 0,
+ RK3328_CLKSEL_CON(50), 6, 2, MFLAGS, 0, 5, DFLAGS,
+ RK3328_CLKGATE_CON(6), 5, GFLAGS),
+ FACTOR_GATE(HCLK_VPU_PRE, "hclk_vpu_pre", "aclk_vpu_pre", 0, 1, 4,
+ RK3328_CLKGATE_CON(11), 8, GFLAGS),
+ GATE(ACLK_VPU, "aclk_vpu", "aclk_vpu_pre", CLK_SET_RATE_PARENT,
+ RK3328_CLKGATE_CON(23), 0, GFLAGS),
+ GATE(HCLK_VPU, "hclk_vpu", "hclk_vpu_pre", CLK_SET_RATE_PARENT,
+ RK3328_CLKGATE_CON(23), 1, GFLAGS),
+ GATE(0, "aclk_vpu_niu", "aclk_vpu_pre", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(23), 2, GFLAGS),
+ GATE(0, "hclk_vpu_niu", "hclk_vpu_pre", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(23), 3, GFLAGS),
+
+ COMPOSITE(ACLK_RKVENC, "aclk_rkvenc", mux_4plls_p, 0,
+ RK3328_CLKSEL_CON(51), 6, 2, MFLAGS, 0, 5, DFLAGS,
+ RK3328_CLKGATE_CON(6), 3, GFLAGS),
+ FACTOR_GATE(HCLK_RKVENC, "hclk_rkvenc", "aclk_rkvenc", 0, 1, 4,
+ RK3328_CLKGATE_CON(11), 4, GFLAGS),
+ GATE(0, "aclk_rkvenc_niu", "aclk_rkvenc", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(25), 0, GFLAGS),
+ GATE(0, "hclk_rkvenc_niu", "hclk_rkvenc", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(25), 1, GFLAGS),
+ GATE(ACLK_H265, "aclk_h265", "aclk_rkvenc", 0,
+ RK3328_CLKGATE_CON(25), 0, GFLAGS),
+ GATE(PCLK_H265, "pclk_h265", "hclk_rkvenc", 0,
+ RK3328_CLKGATE_CON(25), 1, GFLAGS),
+ GATE(ACLK_H264, "aclk_h264", "aclk_rkvenc", 0,
+ RK3328_CLKGATE_CON(25), 0, GFLAGS),
+ GATE(HCLK_H264, "hclk_h264", "hclk_rkvenc", 0,
+ RK3328_CLKGATE_CON(25), 1, GFLAGS),
+ GATE(ACLK_AXISRAM, "aclk_axisram", "aclk_rkvenc", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(25), 0, GFLAGS),
+
+ COMPOSITE(SCLK_VENC_CORE, "sclk_venc_core", mux_4plls_p, 0,
+ RK3328_CLKSEL_CON(51), 14, 2, MFLAGS, 8, 5, DFLAGS,
+ RK3328_CLKGATE_CON(6), 4, GFLAGS),
+
+ COMPOSITE(SCLK_VENC_DSP, "sclk_venc_dsp", mux_4plls_p, 0,
+ RK3328_CLKSEL_CON(52), 14, 2, MFLAGS, 8, 5, DFLAGS,
+ RK3328_CLKGATE_CON(6), 7, GFLAGS),
+
+ /*
+ * Clock-Architecture Diagram 6
+ */
+ /* PD_VIO */
+ COMPOSITE(ACLK_VIO_PRE, "aclk_vio_pre", mux_4plls_p, 0,
+ RK3328_CLKSEL_CON(37), 6, 2, MFLAGS, 0, 5, DFLAGS,
+ RK3328_CLKGATE_CON(5), 2, GFLAGS),
+ DIV(HCLK_VIO_PRE, "hclk_vio_pre", "aclk_vio_pre", 0,
+ RK3328_CLKSEL_CON(37), 8, 5, DFLAGS),
+
+ COMPOSITE(ACLK_RGA_PRE, "aclk_rga_pre", mux_4plls_p, 0,
+ RK3328_CLKSEL_CON(36), 14, 2, MFLAGS, 8, 5, DFLAGS,
+ RK3328_CLKGATE_CON(5), 0, GFLAGS),
+ COMPOSITE(SCLK_RGA, "clk_rga", mux_4plls_p, 0,
+ RK3328_CLKSEL_CON(36), 6, 2, MFLAGS, 0, 5, DFLAGS,
+ RK3328_CLKGATE_CON(5), 1, GFLAGS),
+ COMPOSITE(ACLK_VOP_PRE, "aclk_vop_pre", mux_4plls_p, 0,
+ RK3328_CLKSEL_CON(39), 6, 2, MFLAGS, 0, 5, DFLAGS,
+ RK3328_CLKGATE_CON(5), 5, GFLAGS),
+ GATE(0, "clk_hdmi_sfc", "xin24m", 0,
+ RK3328_CLKGATE_CON(5), 4, GFLAGS),
+
+ COMPOSITE_NODIV(0, "clk_cif_src", mux_2plls_p, 0,
+ RK3328_CLKSEL_CON(42), 7, 1, MFLAGS,
+ RK3328_CLKGATE_CON(5), 3, GFLAGS),
+ COMPOSITE_NOGATE(SCLK_CIF_OUT, "clk_cif_out", mux_sclk_cif_p,
+ CLK_SET_RATE_PARENT,
+ RK3328_CLKSEL_CON(42), 5, 1, MFLAGS, 0, 5, DFLAGS),
+
+ COMPOSITE(DCLK_LCDC_SRC, "dclk_lcdc_src", mux_gpll_cpll_p, 0,
+ RK3328_CLKSEL_CON(40), 0, 1, MFLAGS, 8, 8, DFLAGS,
+ RK3328_CLKGATE_CON(5), 6, GFLAGS),
+ DIV(DCLK_HDMIPHY, "dclk_hdmiphy", "dclk_lcdc_src", 0,
+ RK3328_CLKSEL_CON(40), 3, 3, DFLAGS),
+ MUX(DCLK_LCDC, "dclk_lcdc", mux_dclk_lcdc_p, 0,
+ RK3328_CLKSEL_CON(40), 1, 1, MFLAGS),
+
+ /*
+ * Clock-Architecture Diagram 7
+ */
+ /* PD_PERI */
+ GATE(0, "gpll_peri", "gpll", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(4), 0, GFLAGS),
+ GATE(0, "cpll_peri", "cpll", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(4), 1, GFLAGS),
+ GATE(0, "hdmiphy_peri", "hdmiphy", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(4), 2, GFLAGS),
+ COMPOSITE_NOGATE(ACLK_PERI_PRE, "aclk_peri_pre", mux_aclk_peri_pre_p, 0,
+ RK3328_CLKSEL_CON(28), 6, 2, MFLAGS, 0, 5, DFLAGS),
+ COMPOSITE_NOMUX(PCLK_PERI, "pclk_peri", "aclk_peri_pre",
+ CLK_IGNORE_UNUSED,
+ RK3328_CLKSEL_CON(29), 0, 2, DFLAGS,
+ RK3328_CLKGATE_CON(10), 2, GFLAGS),
+ COMPOSITE_NOMUX(HCLK_PERI, "hclk_peri", "aclk_peri_pre",
+ CLK_IGNORE_UNUSED,
+ RK3328_CLKSEL_CON(29), 4, 3, DFLAGS,
+ RK3328_CLKGATE_CON(10), 1, GFLAGS),
+ GATE(ACLK_PERI, "aclk_peri", "aclk_peri_pre",
+ CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT,
+ RK3328_CLKGATE_CON(10), 0, GFLAGS),
+
+ COMPOSITE(SCLK_SDMMC, "clk_sdmmc", mux_2plls_24m_u480m_p, 0,
+ RK3328_CLKSEL_CON(30), 8, 2, MFLAGS, 0, 8, DFLAGS,
+ RK3328_CLKGATE_CON(4), 3, GFLAGS),
+
+ COMPOSITE(SCLK_SDIO, "clk_sdio", mux_2plls_24m_u480m_p, 0,
+ RK3328_CLKSEL_CON(31), 8, 2, MFLAGS, 0, 8, DFLAGS,
+ RK3328_CLKGATE_CON(4), 4, GFLAGS),
+
+ COMPOSITE(SCLK_EMMC, "clk_emmc", mux_2plls_24m_u480m_p, 0,
+ RK3328_CLKSEL_CON(32), 8, 2, MFLAGS, 0, 8, DFLAGS,
+ RK3328_CLKGATE_CON(4), 5, GFLAGS),
+
+ COMPOSITE(SCLK_SDMMC_EXT, "clk_sdmmc_ext",
+ mux_2plls_24m_u480m_p, 0,
+ RK3328_CLKSEL_CON(43), 8, 2, MFLAGS, 0, 8, DFLAGS,
+ RK3328_CLKGATE_CON(4), 10, GFLAGS),
+
+ COMPOSITE(SCLK_REF_USB3OTG_SRC, "clk_ref_usb3otg_src", mux_2plls_p, 0,
+ RK3328_CLKSEL_CON(45), 7, 1, MFLAGS, 0, 7, DFLAGS,
+ RK3328_CLKGATE_CON(4), 9, GFLAGS),
+
+ MUX(SCLK_REF_USB3OTG, "clk_ref_usb3otg",
+ mux_ref_usb3otg_src_p, CLK_SET_RATE_PARENT,
+ RK3328_CLKSEL_CON(45), 8, 1, MFLAGS),
+
+ GATE(SCLK_USB3OTG_REF, "clk_usb3otg_ref", "xin24m", 0,
+ RK3328_CLKGATE_CON(4), 7, GFLAGS),
+
+ COMPOSITE(SCLK_USB3OTG_SUSPEND, "clk_usb3otg_suspend",
+ mux_xin24m_32k_p, 0,
+ RK3328_CLKSEL_CON(33), 15, 1, MFLAGS, 0, 10, DFLAGS,
+ RK3328_CLKGATE_CON(4), 8, GFLAGS),
+
+ /*
+ * Clock-Architecture Diagram 8
+ */
+ /* PD_GMAC */
+
+ COMPOSITE(ACLK_GMAC, "aclk_gmac", mux_2plls_hdmiphy_p, 0,
+ RK3328_CLKSEL_CON(35), 6, 2, MFLAGS, 0, 5, DFLAGS,
+ RK3328_CLKGATE_CON(3), 2, GFLAGS),
+ COMPOSITE_NOMUX(PCLK_GMAC, "pclk_gmac", "aclk_gmac", 0,
+ RK3328_CLKSEL_CON(25), 8, 3, DFLAGS,
+ RK3328_CLKGATE_CON(9), 0, GFLAGS),
+
+ COMPOSITE(SCLK_MAC2IO_SRC, "clk_mac2io_src", mux_2plls_p, 0,
+ RK3328_CLKSEL_CON(27), 7, 1, MFLAGS, 0, 5, DFLAGS,
+ RK3328_CLKGATE_CON(3), 1, GFLAGS),
+ GATE(SCLK_MAC2IO_REF, "clk_mac2io_ref", "clk_mac2io", 0,
+ RK3328_CLKGATE_CON(9), 7, GFLAGS),
+ GATE(SCLK_MAC2IO_RX, "clk_mac2io_rx", "clk_mac2io", 0,
+ RK3328_CLKGATE_CON(9), 4, GFLAGS),
+ GATE(SCLK_MAC2IO_TX, "clk_mac2io_tx", "clk_mac2io", 0,
+ RK3328_CLKGATE_CON(9), 5, GFLAGS),
+ GATE(SCLK_MAC2IO_REFOUT, "clk_mac2io_refout", "clk_mac2io", 0,
+ RK3328_CLKGATE_CON(9), 6, GFLAGS),
+ COMPOSITE(SCLK_MAC2IO_OUT, "clk_mac2io_out", mux_2plls_p, 0,
+ RK3328_CLKSEL_CON(27), 15, 1, MFLAGS, 8, 5, DFLAGS,
+ RK3328_CLKGATE_CON(3), 5, GFLAGS),
+
+ COMPOSITE(SCLK_MAC2PHY_SRC, "clk_mac2phy_src", mux_2plls_p, 0,
+ RK3328_CLKSEL_CON(26), 7, 1, MFLAGS, 0, 5, DFLAGS,
+ RK3328_CLKGATE_CON(3), 0, GFLAGS),
+ GATE(SCLK_MAC2PHY_REF, "clk_mac2phy_ref", "clk_mac2phy", 0,
+ RK3328_CLKGATE_CON(9), 3, GFLAGS),
+ GATE(SCLK_MAC2PHY_RXTX, "clk_mac2phy_rxtx", "clk_mac2phy", 0,
+ RK3328_CLKGATE_CON(9), 1, GFLAGS),
+ COMPOSITE_NOMUX(SCLK_MAC2PHY_OUT, "clk_mac2phy_out", "clk_mac2phy", 0,
+ RK3328_CLKSEL_CON(26), 8, 2, DFLAGS,
+ RK3328_CLKGATE_CON(9), 2, GFLAGS),
+
+ FACTOR(0, "xin12m", "xin24m", 0, 1, 2),
+
+ /*
+ * Clock-Architecture Diagram 9
+ */
+
+ /* PD_VOP */
+ GATE(ACLK_RGA, "aclk_rga", "aclk_rga_pre", 0,
+ RK3328_CLKGATE_CON(21), 10, GFLAGS),
+ GATE(0, "aclk_rga_niu", "aclk_rga_pre", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(22), 3, GFLAGS),
+ GATE(ACLK_VOP, "aclk_vop", "aclk_vop_pre", 0,
+ RK3328_CLKGATE_CON(21), 2, GFLAGS),
+ GATE(0, "aclk_vop_niu", "aclk_vop_pre", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(21), 4, GFLAGS),
+
+ GATE(ACLK_IEP, "aclk_iep", "aclk_vio_pre", 0,
+ RK3328_CLKGATE_CON(21), 6, GFLAGS),
+ GATE(ACLK_CIF, "aclk_cif", "aclk_vio_pre", 0,
+ RK3328_CLKGATE_CON(21), 8, GFLAGS),
+ GATE(ACLK_HDCP, "aclk_hdcp", "aclk_vio_pre", 0,
+ RK3328_CLKGATE_CON(21), 15, GFLAGS),
+ GATE(0, "aclk_vio_niu", "aclk_vio_pre", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(22), 2, GFLAGS),
+
+ GATE(HCLK_VOP, "hclk_vop", "hclk_vio_pre", 0,
+ RK3328_CLKGATE_CON(21), 3, GFLAGS),
+ GATE(0, "hclk_vop_niu", "hclk_vio_pre", 0,
+ RK3328_CLKGATE_CON(21), 5, GFLAGS),
+ GATE(HCLK_IEP, "hclk_iep", "hclk_vio_pre", 0,
+ RK3328_CLKGATE_CON(21), 7, GFLAGS),
+ GATE(HCLK_CIF, "hclk_cif", "hclk_vio_pre", 0,
+ RK3328_CLKGATE_CON(21), 9, GFLAGS),
+ GATE(HCLK_RGA, "hclk_rga", "hclk_vio_pre", 0,
+ RK3328_CLKGATE_CON(21), 11, GFLAGS),
+ GATE(0, "hclk_ahb1tom", "hclk_vio_pre", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(21), 12, GFLAGS),
+ GATE(0, "pclk_vio_h2p", "hclk_vio_pre", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(21), 13, GFLAGS),
+ GATE(0, "hclk_vio_h2p", "hclk_vio_pre", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(21), 14, GFLAGS),
+ GATE(HCLK_HDCP, "hclk_hdcp", "hclk_vio_pre", 0,
+ RK3328_CLKGATE_CON(22), 0, GFLAGS),
+ GATE(HCLK_VIO, "hclk_vio", "hclk_vio_pre", 0,
+ RK3328_CLKGATE_CON(22), 1, GFLAGS),
+ GATE(PCLK_HDMI, "pclk_hdmi", "hclk_vio_pre", 0,
+ RK3328_CLKGATE_CON(22), 4, GFLAGS),
+ GATE(PCLK_HDCP, "pclk_hdcp", "hclk_vio_pre", 0,
+ RK3328_CLKGATE_CON(22), 5, GFLAGS),
+
+ /* PD_PERI */
+ GATE(0, "aclk_peri_noc", "aclk_peri", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(19), 11, GFLAGS),
+ GATE(ACLK_USB3OTG, "aclk_usb3otg", "aclk_peri", 0,
+ RK3328_CLKGATE_CON(19), 4, GFLAGS),
+
+ GATE(HCLK_SDMMC, "hclk_sdmmc", "hclk_peri", 0,
+ RK3328_CLKGATE_CON(19), 0, GFLAGS),
+ GATE(HCLK_SDIO, "hclk_sdio", "hclk_peri", 0,
+ RK3328_CLKGATE_CON(19), 1, GFLAGS),
+ GATE(HCLK_EMMC, "hclk_emmc", "hclk_peri", 0,
+ RK3328_CLKGATE_CON(19), 2, GFLAGS),
+ GATE(HCLK_SDMMC_EXT, "hclk_sdmmc_ext", "hclk_peri", 0,
+ RK3328_CLKGATE_CON(19), 15, GFLAGS),
+ GATE(HCLK_HOST0, "hclk_host0", "hclk_peri", 0,
+ RK3328_CLKGATE_CON(19), 6, GFLAGS),
+ GATE(HCLK_HOST0_ARB, "hclk_host0_arb", "hclk_peri", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(19), 7, GFLAGS),
+ GATE(HCLK_OTG, "hclk_otg", "hclk_peri", 0,
+ RK3328_CLKGATE_CON(19), 8, GFLAGS),
+ GATE(HCLK_OTG_PMU, "hclk_otg_pmu", "hclk_peri", 0,
+ RK3328_CLKGATE_CON(19), 9, GFLAGS),
+ GATE(0, "hclk_peri_niu", "hclk_peri", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(19), 12, GFLAGS),
+ GATE(0, "pclk_peri_niu", "hclk_peri", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(19), 13, GFLAGS),
+
+ /* PD_GMAC */
+ GATE(ACLK_MAC2PHY, "aclk_mac2phy", "aclk_gmac", 0,
+ RK3328_CLKGATE_CON(26), 0, GFLAGS),
+ GATE(ACLK_MAC2IO, "aclk_mac2io", "aclk_gmac", 0,
+ RK3328_CLKGATE_CON(26), 2, GFLAGS),
+ GATE(0, "aclk_gmac_niu", "aclk_gmac", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(26), 4, GFLAGS),
+ GATE(PCLK_MAC2PHY, "pclk_mac2phy", "pclk_gmac", 0,
+ RK3328_CLKGATE_CON(26), 1, GFLAGS),
+ GATE(PCLK_MAC2IO, "pclk_mac2io", "pclk_gmac", 0,
+ RK3328_CLKGATE_CON(26), 3, GFLAGS),
+ GATE(0, "pclk_gmac_niu", "pclk_gmac", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(26), 5, GFLAGS),
+
+ /* PD_BUS */
+ GATE(0, "aclk_bus_niu", "aclk_bus_pre", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(15), 12, GFLAGS),
+ GATE(ACLK_DCF, "aclk_dcf", "aclk_bus_pre", 0,
+ RK3328_CLKGATE_CON(15), 11, GFLAGS),
+ GATE(ACLK_TSP, "aclk_tsp", "aclk_bus_pre", 0,
+ RK3328_CLKGATE_CON(17), 12, GFLAGS),
+ GATE(0, "aclk_intmem", "aclk_bus_pre", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(15), 0, GFLAGS),
+ GATE(ACLK_DMAC, "aclk_dmac_bus", "aclk_bus_pre", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(15), 1, GFLAGS),
+
+ GATE(0, "hclk_rom", "hclk_bus_pre", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(15), 2, GFLAGS),
+ GATE(HCLK_I2S0_8CH, "hclk_i2s0_8ch", "hclk_bus_pre", 0,
+ RK3328_CLKGATE_CON(15), 3, GFLAGS),
+ GATE(HCLK_I2S1_8CH, "hclk_i2s1_8ch", "hclk_bus_pre", 0,
+ RK3328_CLKGATE_CON(15), 4, GFLAGS),
+ GATE(HCLK_I2S2_2CH, "hclk_i2s2_2ch", "hclk_bus_pre", 0,
+ RK3328_CLKGATE_CON(15), 5, GFLAGS),
+ GATE(HCLK_SPDIF_8CH, "hclk_spdif_8ch", "hclk_bus_pre", 0,
+ RK3328_CLKGATE_CON(15), 6, GFLAGS),
+ GATE(HCLK_TSP, "hclk_tsp", "hclk_bus_pre", 0,
+ RK3328_CLKGATE_CON(17), 11, GFLAGS),
+ GATE(HCLK_CRYPTO_MST, "hclk_crypto_mst", "hclk_bus_pre", 0,
+ RK3328_CLKGATE_CON(15), 7, GFLAGS),
+ GATE(HCLK_CRYPTO_SLV, "hclk_crypto_slv", "hclk_bus_pre", 0,
+ RK3328_CLKGATE_CON(15), 8, GFLAGS),
+ GATE(0, "hclk_bus_niu", "hclk_bus_pre", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(15), 13, GFLAGS),
+ GATE(HCLK_PDM, "hclk_pdm", "hclk_bus_pre", 0,
+ RK3328_CLKGATE_CON(28), 0, GFLAGS),
+
+ GATE(0, "pclk_bus_niu", "pclk_bus", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(15), 14, GFLAGS),
+ GATE(0, "pclk_efuse", "pclk_bus", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(15), 9, GFLAGS),
+ GATE(0, "pclk_otp", "pclk_bus", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(28), 4, GFLAGS),
+ GATE(PCLK_I2C0, "pclk_i2c0", "pclk_bus", 0,
+ RK3328_CLKGATE_CON(15), 10, GFLAGS),
+ GATE(PCLK_I2C1, "pclk_i2c1", "pclk_bus", 0,
+ RK3328_CLKGATE_CON(16), 0, GFLAGS),
+ GATE(PCLK_I2C2, "pclk_i2c2", "pclk_bus", 0,
+ RK3328_CLKGATE_CON(16), 1, GFLAGS),
+ GATE(PCLK_I2C3, "pclk_i2c3", "pclk_bus", 0,
+ RK3328_CLKGATE_CON(16), 2, GFLAGS),
+ GATE(PCLK_TIMER, "pclk_timer0", "pclk_bus", 0,
+ RK3328_CLKGATE_CON(16), 3, GFLAGS),
+ GATE(0, "pclk_stimer", "pclk_bus", 0,
+ RK3328_CLKGATE_CON(16), 4, GFLAGS),
+ GATE(PCLK_SPI, "pclk_spi", "pclk_bus", 0,
+ RK3328_CLKGATE_CON(16), 5, GFLAGS),
+ GATE(PCLK_PWM, "pclk_rk_pwm", "pclk_bus", 0,
+ RK3328_CLKGATE_CON(16), 6, GFLAGS),
+ GATE(PCLK_GPIO0, "pclk_gpio0", "pclk_bus", 0,
+ RK3328_CLKGATE_CON(16), 7, GFLAGS),
+ GATE(PCLK_GPIO1, "pclk_gpio1", "pclk_bus", 0,
+ RK3328_CLKGATE_CON(16), 8, GFLAGS),
+ GATE(PCLK_GPIO2, "pclk_gpio2", "pclk_bus", 0,
+ RK3328_CLKGATE_CON(16), 9, GFLAGS),
+ GATE(PCLK_GPIO3, "pclk_gpio3", "pclk_bus", 0,
+ RK3328_CLKGATE_CON(16), 10, GFLAGS),
+ GATE(PCLK_UART0, "pclk_uart0", "pclk_bus", 0,
+ RK3328_CLKGATE_CON(16), 11, GFLAGS),
+ GATE(PCLK_UART1, "pclk_uart1", "pclk_bus", 0,
+ RK3328_CLKGATE_CON(16), 12, GFLAGS),
+ GATE(PCLK_UART2, "pclk_uart2", "pclk_bus", 0,
+ RK3328_CLKGATE_CON(16), 13, GFLAGS),
+ GATE(PCLK_TSADC, "pclk_tsadc", "pclk_bus", 0,
+ RK3328_CLKGATE_CON(16), 14, GFLAGS),
+ GATE(PCLK_DCF, "pclk_dcf", "pclk_bus", 0,
+ RK3328_CLKGATE_CON(16), 15, GFLAGS),
+ GATE(PCLK_GRF, "pclk_grf", "pclk_bus", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(17), 0, GFLAGS),
+ GATE(0, "pclk_cru", "pclk_bus", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(17), 4, GFLAGS),
+ GATE(0, "pclk_sgrf", "pclk_bus", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(17), 6, GFLAGS),
+ GATE(0, "pclk_sim", "pclk_bus", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(17), 10, GFLAGS),
+ GATE(PCLK_SARADC, "pclk_saradc", "pclk_bus", 0,
+ RK3328_CLKGATE_CON(17), 15, GFLAGS),
+ GATE(0, "pclk_pmu", "pclk_bus", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(28), 3, GFLAGS),
+
+ GATE(PCLK_USB3PHY_OTG, "pclk_usb3phy_otg", "pclk_phy_pre", 0,
+ RK3328_CLKGATE_CON(28), 1, GFLAGS),
+ GATE(PCLK_USB3PHY_PIPE, "pclk_usb3phy_pipe", "pclk_phy_pre", 0,
+ RK3328_CLKGATE_CON(28), 2, GFLAGS),
+ GATE(PCLK_USB3_GRF, "pclk_usb3_grf", "pclk_phy_pre", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(17), 2, GFLAGS),
+ GATE(PCLK_USB2_GRF, "pclk_usb2_grf", "pclk_phy_pre", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(17), 14, GFLAGS),
+ GATE(0, "pclk_ddrphy", "pclk_phy_pre", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(17), 13, GFLAGS),
+ GATE(0, "pclk_acodecphy", "pclk_phy_pre", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(17), 5, GFLAGS),
+ GATE(PCLK_HDMIPHY, "pclk_hdmiphy", "pclk_phy_pre", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(17), 7, GFLAGS),
+ GATE(0, "pclk_vdacphy", "pclk_phy_pre", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(17), 8, GFLAGS),
+ GATE(0, "pclk_phy_niu", "pclk_phy_pre", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(15), 15, GFLAGS),
+
+ /* PD_MMC */
+ MMC(SCLK_SDMMC_DRV, "sdmmc_drv", "sclk_sdmmc",
+ RK3328_SDMMC_CON0, 1),
+ MMC(SCLK_SDMMC_SAMPLE, "sdmmc_sample", "sclk_sdmmc",
+ RK3328_SDMMC_CON1, 1),
+
+ MMC(SCLK_SDIO_DRV, "sdio_drv", "sclk_sdio",
+ RK3328_SDIO_CON0, 1),
+ MMC(SCLK_SDIO_SAMPLE, "sdio_sample", "sclk_sdio",
+ RK3328_SDIO_CON1, 1),
+
+ MMC(SCLK_EMMC_DRV, "emmc_drv", "sclk_emmc",
+ RK3328_EMMC_CON0, 1),
+ MMC(SCLK_EMMC_SAMPLE, "emmc_sample", "sclk_emmc",
+ RK3328_EMMC_CON1, 1),
+
+ MMC(SCLK_SDMMC_EXT_DRV, "sdmmc_ext_drv", "sclk_sdmmc_ext",
+ RK3328_SDMMC_EXT_CON0, 1),
+ MMC(SCLK_SDMMC_EXT_SAMPLE, "sdmmc_ext_sample", "sclk_sdmmc_ext",
+ RK3328_SDMMC_EXT_CON1, 1),
+};
+
+static struct rockchip_clk_branch rk3328_clk_grf_branches[] __initdata = {
+ /*
+ * GRF CRU Clock-Architecture
+ */
+ MUX(SCLK_MAC2IO, "clk_mac2io", mux_mac2io_src_p, 0,
+ RK3328_GRF_MAC_CON1, 10, 1, MFLAGS),
+ MUX(SCLK_MAC2PHY, "clk_mac2phy", mux_mac2phy_src_p, 0,
+ RK3328_GRF_MAC_CON2, 10, 1, MFLAGS),
+};
+
+static const char *const rk3328_critical_clocks[] __initconst = {
+ "aclk_bus",
+ "pclk_bus",
+ "hclk_bus",
+ "aclk_peri",
+ "hclk_peri",
+ "pclk_peri",
+ "pclk_dbg",
+ "aclk_core_niu",
+ "aclk_gic400",
+ "aclk_intmem",
+ "hclk_rom",
+ "pclk_grf",
+ "pclk_cru",
+ "pclk_sgrf",
+ "pclk_timer0",
+ "clk_timer0",
+ "pclk_ddr_msch",
+ "pclk_ddr_mon",
+ "pclk_ddr_grf",
+ "clk_ddrupctl",
+ "clk_ddrmsch",
+ "hclk_ahb1tom",
+ "clk_jtag",
+ "pclk_ddrphy",
+ "pclk_pmu",
+ "hclk_otg_pmu",
+ "aclk_rga_niu",
+ "pclk_vio_h2p",
+ "hclk_vio_h2p",
+};
+
+static void __iomem *rk3328_cru_base;
+
+void rk3328_dump_cru(void)
+{
+ if (rk3328_cru_base) {
+ pr_warn("CRU:\n");
+ print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET,
+ 32, 4, rk3328_cru_base,
+ 0x400, false);
+ }
+}
+EXPORT_SYMBOL_GPL(rk3328_dump_cru);
+
+static int rk3328_clk_panic(struct notifier_block *this,
+ unsigned long ev, void *ptr)
+{
+ rk3328_dump_cru();
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block rk3328_clk_panic_block = {
+ .notifier_call = rk3328_clk_panic,
+};
+
+static void __init rk3328_clk_init(struct device_node *np)
+{
+ struct rockchip_clk_provider *ctx;
+ void __iomem *reg_base;
+
+ reg_base = of_iomap(np, 0);
+ if (!reg_base) {
+ pr_err("%s: could not map cru region\n", __func__);
+ return;
+ }
+
+ rk3328_cru_base = reg_base;
+
+ ctx = rockchip_clk_init(np, reg_base, CLK_NR_CLKS);
+ if (IS_ERR(ctx)) {
+ pr_err("%s: rockchip clk init failed\n", __func__);
+ iounmap(reg_base);
+ return;
+ }
+
+ rockchip_clk_register_plls(ctx, rk3328_pll_clks,
+ ARRAY_SIZE(rk3328_pll_clks),
+ RK3328_GRF_SOC_STATUS0);
+ rockchip_clk_register_branches(ctx, rk3328_clk_branches,
+ ARRAY_SIZE(rk3328_clk_branches));
+ rockchip_clk_protect_critical(rk3328_critical_clocks,
+ ARRAY_SIZE(rk3328_critical_clocks));
+
+ rockchip_clk_register_armclk(ctx, ARMCLK, "armclk",
+ mux_armclk_p, ARRAY_SIZE(mux_armclk_p),
+ &rk3328_cpuclk_data, rk3328_cpuclk_rates,
+ ARRAY_SIZE(rk3328_cpuclk_rates));
+
+ rockchip_register_softrst(np, 11, reg_base + RK3328_SOFTRST_CON(0),
+ ROCKCHIP_SOFTRST_HIWORD_MASK);
+
+ rockchip_register_restart_notifier(ctx, RK3328_GLB_SRST_FST, NULL);
+
+ rockchip_clk_of_add_provider(np, ctx);
+
+ atomic_notifier_chain_register(&panic_notifier_list,
+ &rk3328_clk_panic_block);
+}
+
+CLK_OF_DECLARE(rk3328_cru, "rockchip,rk3328-cru", rk3328_clk_init);
+
+static void __init rk3328_grf_clk_init(struct device_node *np)
+{
+ struct rockchip_clk_provider *ctx;
+ void __iomem *reg_base;
+
+ reg_base = of_iomap(np, 0);
+ if (!reg_base) {
+ pr_err("%s: could not map cru pmu region\n", __func__);
+ return;
+ }
+
+ ctx = rockchip_clk_init(np, reg_base, CLKGRF_NR_CLKS);
+ if (IS_ERR(ctx)) {
+ pr_err("%s: rockchip pmu clk init failed\n", __func__);
+ return;
+ }
+
+ rockchip_clk_register_branches(ctx, rk3328_clk_grf_branches,
+ ARRAY_SIZE(rk3328_clk_grf_branches));
+
+ rockchip_clk_of_add_provider(np, ctx);
+}
+
+CLK_OF_DECLARE(rk3328_cru_grf, "rockchip,rk3328-grf", rk3328_grf_clk_init);
diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h
index d67eecc4ade9..7225997f8d52 100644
--- a/drivers/clk/rockchip/clk.h
+++ b/drivers/clk/rockchip/clk.h
@@ -91,6 +91,28 @@
#define RK3288_EMMC_CON0 0x218
#define RK3288_EMMC_CON1 0x21c
+#define RK3328_PLL_CON(x) RK2928_PLL_CON(x)
+#define RK3328_CLKSEL_CON(x) ((x) * 0x4 + 0x100)
+#define RK3328_CLKGATE_CON(x) ((x) * 0x4 + 0x200)
+#define RK3328_GRFCLKSEL_CON(x) ((x) * 0x4 + 0x100)
+#define RK3328_GLB_SRST_FST 0x9c
+#define RK3328_GLB_SRST_SND 0x98
+#define RK3328_SOFTRST_CON(x) ((x) * 0x4 + 0x300)
+#define RK3328_MODE_CON 0x80
+#define RK3328_MISC_CON 0x84
+#define RK3328_DIV_ACLKM_MASK 0x7
+#define RK3328_DIV_ACLKM_SHIFT 4
+#define RK3328_DIV_PCLK_DBG_MASK 0xf
+#define RK3328_DIV_PCLK_DBG_SHIFT 0
+#define RK3328_SDMMC_CON0 0x380
+#define RK3328_SDMMC_CON1 0x384
+#define RK3328_SDIO_CON0 0x388
+#define RK3328_SDIO_CON1 0x38c
+#define RK3328_EMMC_CON0 0x390
+#define RK3328_EMMC_CON1 0x394
+#define RK3328_SDMMC_EXT_CON0 0x398
+#define RK3328_SDMMC_EXT_CON1 0x39C
+
#define RK3368_PLL_CON(x) RK2928_PLL_CON(x)
#define RK3368_CLKSEL_CON(x) ((x) * 0x4 + 0x100)
#define RK3368_CLKGATE_CON(x) ((x) * 0x4 + 0x200)
@@ -130,6 +152,7 @@
enum rockchip_pll_type {
pll_rk3036,
pll_rk3066,
+ pll_rk3328,
pll_rk3399,
};
--
1.9.1
^ permalink raw reply related
* [PATCH v2 4/4] clk: rockchip: add new pll-type for rk3328
From: Elaine Zhang @ 2016-12-19 1:56 UTC (permalink / raw)
To: heiko, mturquette, sboyd, xf
Cc: robh+dt, mark.rutland, linux-clk, linux-arm-kernel, devicetree,
huangtao, xxx, cl, linux-rockchip, linux-kernel, Elaine Zhang
In-Reply-To: <1482112573-11613-1-git-send-email-zhangqing@rock-chips.com>
The rk3328's pll and clock are similar with rk3036's,
it different with pll_mode_mask,there are different
control registers bit,
so these should be independent and separate from
the series of rk3328s.
Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
---
drivers/clk/rockchip/clk-pll.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c
index 6ed605776abd..9650c75f61d1 100644
--- a/drivers/clk/rockchip/clk-pll.c
+++ b/drivers/clk/rockchip/clk-pll.c
@@ -29,6 +29,7 @@
#define PLL_MODE_SLOW 0x0
#define PLL_MODE_NORM 0x1
#define PLL_MODE_DEEP 0x2
+#define PLL_RK3328_MODE_MASK 0x1
struct rockchip_clk_pll {
struct clk_hw hw;
@@ -865,13 +866,17 @@ struct clk *rockchip_clk_register_pll(struct rockchip_clk_provider *ctx,
pll_mux = &pll->pll_mux;
pll_mux->reg = ctx->reg_base + mode_offset;
pll_mux->shift = mode_shift;
- pll_mux->mask = PLL_MODE_MASK;
+ if (pll_type == pll_rk3328)
+ pll_mux->mask = PLL_RK3328_MODE_MASK;
+ else
+ pll_mux->mask = PLL_MODE_MASK;
pll_mux->flags = 0;
pll_mux->lock = &ctx->lock;
pll_mux->hw.init = &init;
if (pll_type == pll_rk3036 ||
pll_type == pll_rk3066 ||
+ pll_type == pll_rk3328 ||
pll_type == pll_rk3399)
pll_mux->flags |= CLK_MUX_HIWORD_MASK;
@@ -929,6 +934,12 @@ struct clk *rockchip_clk_register_pll(struct rockchip_clk_provider *ctx,
else
init.ops = &rockchip_rk3066_pll_clk_ops;
break;
+ case pll_rk3328:
+ if (!pll->rate_table || IS_ERR(ctx->grf))
+ init.ops = &rockchip_rk3036_pll_clk_norate_ops;
+ else
+ init.ops = &rockchip_rk3036_pll_clk_ops;
+ break;
case pll_rk3399:
if (!pll->rate_table)
init.ops = &rockchip_rk3399_pll_clk_norate_ops;
--
1.9.1
^ permalink raw reply related
* [PATCH 00/21] MIPS memblock: Remove bootmem code and switch to NO_BOOTMEM
From: Serge Semin @ 2016-12-19 2:07 UTC (permalink / raw)
To: ralf, paul.burton, rabinv, matt.redfearn, james.hogan,
alexander.sverdlin, robh+dt, frowand.list
Cc: Sergey.Semin, linux-mips, devicetree, linux-kernel, Serge Semin
Most of the modern platforms supported by linux kernel have already
been cleaned up of old bootmem allocator by moving to nobootmem
interface wrapping up the memblock. This patchset is the first
attempt to do the similar improvement for MIPS for UMA systems
only.
Even though the porting was performed as much careful as possible
there still might be problem with support of some platforms,
especially Loonson3 or SGI IP27, which perform early memory manager
initialization by their self.
The patchset is split so individual patch being consistent in
functional and buildable ways. But the MIPS early memory manager
will work correctly only either with or without the whole set being
applied. For the same reason a reviewer should not pay much attention
to methods bootmem_init(), arch_mem_init(), paging_init() and
mem_init() until they are fully refactored.
The patchset is applied on top of kernel v4.9.
Signed-off-by: Serge Semin <fancer.lancer@gmail.com>
Serge Semin (21):
MIPS memblock: Unpin dts memblock sanity check method
MIPS memblock: Add dts mem and reserved-mem callbacks
MIPS memblock: Alter traditional add_memory_region() method
MIPS memblock: Alter user-defined memory parameter parser
MIPS memblock: Alter initrd memory reservation method
MIPS memblock: Alter kexec-crashkernel parameters parser
MIPS memblock: Alter elfcorehdr parameters parser
MIPS memblock: Move kernel parameters parser into individual method
MIPS memblock: Move kernel memory reservation to individual method
MIPS memblock: Discard bootmem allocator initialization
MIPS memblock: Add memblock sanity check method
MIPS memblock: Add memblock print outs in debug
MIPS memblock: Add memblock allocator initialization
MIPS memblock: Alter IO resources initialization method
MIPS memblock: Alter weakened MAAR initialization method
MIPS memblock: Alter paging initialization method
MIPS memblock: Alter high memory freeing method
MIPS memblock: Slightly improve buddy allocator init method
MIPS memblock: Add print out method of kernel virtual memory layout
MIPS memblock: Add free low memory test method call
MIPS memblock: Deactivate old bootmem allocator
arch/mips/Kconfig | 2 +-
arch/mips/kernel/prom.c | 32 +-
arch/mips/kernel/setup.c | 958 +++++++++++++++--------------
arch/mips/mm/init.c | 234 ++++---
drivers/of/fdt.c | 47 +-
include/linux/of_fdt.h | 1 +
6 files changed, 739 insertions(+), 535 deletions(-)
--
2.6.6
^ permalink raw reply
* [PATCH 01/21] MIPS memblock: Unpin dts memblock sanity check method
From: Serge Semin @ 2016-12-19 2:07 UTC (permalink / raw)
To: ralf, paul.burton, rabinv, matt.redfearn, james.hogan,
alexander.sverdlin, robh+dt, frowand.list
Cc: Sergey.Semin, linux-mips, devicetree, linux-kernel, Serge Semin
In-Reply-To: <1482113266-13207-1-git-send-email-fancer.lancer@gmail.com>
It's necessary to check whether retrieved from dts memory regions
fits to page alignment and limits restrictions. Sometimes it is
necessary to perform the same checks, but ito add the memory regions
into a different subsystem. MIPS is going to be that case.
Signed-off-by: Serge Semin <fancer.lancer@gmail.com>
---
drivers/of/fdt.c | 47 +++++++++++++++++++++++---------
include/linux/of_fdt.h | 1 +
2 files changed, 35 insertions(+), 13 deletions(-)
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index 1f98156..1ee958f 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -983,44 +983,65 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
#define MAX_MEMBLOCK_ADDR ((phys_addr_t)~0)
#endif
-void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size)
+int __init sanity_check_dt_memory(phys_addr_t *out_base,
+ phys_addr_t *out_size)
{
+ phys_addr_t base = *out_base, size = *out_size;
const u64 phys_offset = MIN_MEMBLOCK_ADDR;
if (!PAGE_ALIGNED(base)) {
if (size < PAGE_SIZE - (base & ~PAGE_MASK)) {
- pr_warn("Ignoring memory block 0x%llx - 0x%llx\n",
+ pr_err("Memblock 0x%llx - 0x%llx isn't page aligned\n",
base, base + size);
- return;
+ return -EINVAL;
}
+ pr_warn("Memblock 0x%llx - 0x%llx shifted to ",
+ base, base + size);
size -= PAGE_SIZE - (base & ~PAGE_MASK);
base = PAGE_ALIGN(base);
+ pr_cont("0x%llx - 0x%llx\n", base, base + size);
}
size &= PAGE_MASK;
if (base > MAX_MEMBLOCK_ADDR) {
- pr_warning("Ignoring memory block 0x%llx - 0x%llx\n",
- base, base + size);
- return;
+ pr_err("Memblock 0x%llx - 0x%llx exceeds max address\n",
+ base, base + size);
+ return -EINVAL;
}
if (base + size - 1 > MAX_MEMBLOCK_ADDR) {
- pr_warning("Ignoring memory range 0x%llx - 0x%llx\n",
- ((u64)MAX_MEMBLOCK_ADDR) + 1, base + size);
+ pr_warn("Memblock 0x%llx - 0x%llx truncated to ",
+ base, base + size);
size = MAX_MEMBLOCK_ADDR - base + 1;
+ pr_cont("0x%llx - 0x%llx\n", base, base + size);
}
if (base + size < phys_offset) {
- pr_warning("Ignoring memory block 0x%llx - 0x%llx\n",
- base, base + size);
- return;
+ pr_err("Memblock 0x%llx - 0x%llx is below phys offset\n",
+ base, base + size);
+ return -EINVAL;
}
+
if (base < phys_offset) {
- pr_warning("Ignoring memory range 0x%llx - 0x%llx\n",
- base, phys_offset);
+ pr_warn("Memblock 0x%llx - 0x%llx truncated to ",
+ base, base + size);
size -= phys_offset - base;
base = phys_offset;
+ pr_cont("0x%llx - 0x%llx\n", base, base + size);
}
+
+ /* Set the output base address and size */
+ *out_base = base;
+ *out_size = size;
+
+ return 0;
+}
+
+void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size)
+{
+ if (sanity_check_dt_memory(&base, &size))
+ return;
+
memblock_add(base, size);
}
diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h
index df9ef38..ddf93c5 100644
--- a/include/linux/of_fdt.h
+++ b/include/linux/of_fdt.h
@@ -84,6 +84,7 @@ extern const void *of_flat_dt_match_machine(const void *default_match,
const void * (*get_next_compat)(const char * const**));
/* Other Prototypes */
+extern int sanity_check_dt_memory(phys_addr_t *base, phys_addr_t *size);
extern void unflatten_device_tree(void);
extern void unflatten_and_copy_device_tree(void);
extern void early_init_devtree(void *);
--
2.6.6
^ permalink raw reply related
* [PATCH 02/21] MIPS memblock: Add dts mem and reserved-mem callbacks
From: Serge Semin @ 2016-12-19 2:07 UTC (permalink / raw)
To: ralf-6z/3iImG2C8G8FEW9MqTrA, paul.burton-1AXoQHu6uovQT0dZR+AlfA,
rabinv-VrBV9hrLPhE, matt.redfearn-1AXoQHu6uovQT0dZR+AlfA,
james.hogan-1AXoQHu6uovQT0dZR+AlfA,
alexander.sverdlin-xNZwKgViW5gAvxtiuMwx3w,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
frowand.list-Re5JQEeQqe8AvxtiuMwx3w
Cc: Sergey.Semin-vHJ8rsvMqnUPfZBKTuL5GA,
linux-mips-6z/3iImG2C8G8FEW9MqTrA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Serge Semin
In-Reply-To: <1482113266-13207-1-git-send-email-fancer.lancer-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
In order to get a structured table of platform devices, it is
widespread amongst modern systems to use fdt'es.
MIPS should support one as well. Particularly /memory/ and
/reserved-memory/ should be analyzed and corresponding regions
registered with memblock subsystem.
Signed-off-by: Serge Semin <fancer.lancer-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
arch/mips/kernel/prom.c | 32 ++++++++++++++++++++++++++++++-
1 file changed, 31 insertions(+), 1 deletion(-)
diff --git a/arch/mips/kernel/prom.c b/arch/mips/kernel/prom.c
index 5fcec30..f21eb8c 100644
--- a/arch/mips/kernel/prom.c
+++ b/arch/mips/kernel/prom.c
@@ -17,6 +17,7 @@
#include <linux/of.h>
#include <linux/of_fdt.h>
#include <linux/of_platform.h>
+#include <linux/memblock.h>
#include <asm/bootinfo.h>
#include <asm/page.h>
@@ -41,7 +42,36 @@ char *mips_get_machine_name(void)
#ifdef CONFIG_USE_OF
void __init early_init_dt_add_memory_arch(u64 base, u64 size)
{
- return add_memory_region(base, size, BOOT_MEM_RAM);
+ /* Check whether specified region is well formed */
+ if (sanity_check_dt_memory(&base, &size))
+ return;
+
+ /* Memory region should be in boot_mem_map, so use the old method */
+ add_memory_region(base, size, BOOT_MEM_RAM);
+}
+
+int __init early_init_dt_reserve_memory_arch(phys_addr_t base,
+ phys_addr_t size, bool nomap)
+{
+ /*
+ * NOTE We don't use add_memory_region() method here, since fdt
+ * reserved-memory regions are declared within already added memory,
+ * while boot_mem_map consists of unique regions
+ */
+
+ /* Check whether region is free. If so just ignore it */
+ if (memblock_is_region_reserved(base, size)) {
+ pr_err("FDT reserve-node %08zx @ %pa overlaps in-use memory\n",
+ (size_t)size, &base);
+ return -EBUSY;
+ }
+
+ /* If it can be mapped, then just reserve the region */
+ if (!nomap)
+ return memblock_reserve(base, size);
+
+ /* Completely remove region if it shouldn't be mapped */
+ return memblock_remove(base, size);
}
void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
--
2.6.6
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH 03/21] MIPS memblock: Alter traditional add_memory_region() method
From: Serge Semin @ 2016-12-19 2:07 UTC (permalink / raw)
To: ralf, paul.burton, rabinv, matt.redfearn, james.hogan,
alexander.sverdlin, robh+dt, frowand.list
Cc: Sergey.Semin, linux-mips, devicetree, linux-kernel, Serge Semin
In-Reply-To: <1482113266-13207-1-git-send-email-fancer.lancer@gmail.com>
There is no safe and fast way to get rid of boot_mem_map usage in
the wide set of platform code. But it's luck, that the architecture
specific code doesn't make any direct changes in the boot_mem_map
structure. Additionally the platform specific code registers the
available memory using traditional add_memory_region() method.
It's obvious, that one needs to be modified adding regions to both
new memblock allocator and old boot_mem_map subsystem. In this way
most of architecture specific code won't be broken.
Signed-off-by: Serge Semin <fancer.lancer@gmail.com>
---
arch/mips/kernel/setup.c | 51 ++++++++++++++++++++++++++++--
1 file changed, 48 insertions(+), 3 deletions(-)
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 084ba6c..9da6f8a 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -82,10 +82,19 @@ static struct resource data_resource = { .name = "Kernel data", };
static void *detect_magic __initdata = detect_memory_region;
+/*
+ * General method to add RAM regions to the system
+ *
+ * NOTE Historically this method has been used to register memory blocks within
+ * MIPS kernel code in the boot_mem_map array. So we need to support it
+ * up until it's discarded from platform-depended code.
+ * On the other hand it might be good to have it, since we can check regions
+ * before actually adding them
+ */
void __init add_memory_region(phys_addr_t start, phys_addr_t size, long type)
{
int x = boot_mem_map.nr_map;
- int i;
+ int ret, i;
/*
* If the region reaches the top of the physical address space, adjust
@@ -94,15 +103,51 @@ void __init add_memory_region(phys_addr_t start, phys_addr_t size, long type)
if (start + size - 1 == (phys_addr_t)ULLONG_MAX)
--size;
- /* Sanity check */
+ /* Sanity check the region */
if (start + size < start) {
pr_warn("Trying to add an invalid memory region, skipped\n");
return;
}
+ /* Make sure the type is supported */
+ if (type != BOOT_MEM_RAM && type != BOOT_MEM_INIT_RAM &&
+ type != BOOT_MEM_ROM_DATA && type != BOOT_MEM_RESERVED) {
+ pr_warn("Invalid type of memory region, skipped\n");
+ return;
+ }
+
/*
- * Try to merge with existing entry, if any.
+ * According to the request_resource logic RAM, INIT and ROM shouldn't
+ * intersect each other but being subset of one memory space
*/
+ if (type != BOOT_MEM_RESERVED && memblock_is_memory(start)) {
+ pr_warn("Drop already added memory region %08zx @ %pa\n",
+ (size_t)size, &start);
+ return;
+ }
+
+ /*
+ * Add the region to the memblock allocator. Reserved regions should be
+ * in the memory as well to be actually reserved.
+ */
+ ret = memblock_add_node(start, size, 0);
+ if (ret < 0) {
+ pr_err("Could't add memblock %08zx @ %pa\n",
+ (size_t)size, &start);
+ return;
+ }
+
+ /* Reserve memory region passed with the corresponding flags */
+ if (type != BOOT_MEM_RAM) {
+ ret = memblock_reserve(start, size);
+ if (ret < 0) {
+ pr_err("Could't reserve memblock %08zx @ %pa\n",
+ (size_t)size, &start);
+ return;
+ }
+ }
+
+ /* Try to combine with existing entry, if any. */
for (i = 0; i < boot_mem_map.nr_map; i++) {
struct boot_mem_map_entry *entry = boot_mem_map.map + i;
unsigned long top;
--
2.6.6
^ permalink raw reply related
* [PATCH 04/21] MIPS memblock: Alter user-defined memory parameter parser
From: Serge Semin @ 2016-12-19 2:07 UTC (permalink / raw)
To: ralf, paul.burton, rabinv, matt.redfearn, james.hogan,
alexander.sverdlin, robh+dt, frowand.list
Cc: Sergey.Semin, linux-mips, devicetree, linux-kernel, Serge Semin
In-Reply-To: <1482113266-13207-1-git-send-email-fancer.lancer@gmail.com>
Both new memblock and boot_mem_map subsystems need to be fully
cleared before a new memory region is added. So the early parser is
correspondingly modified.
Signed-off-by: Serge Semin <fancer.lancer@gmail.com>
---
arch/mips/kernel/setup.c | 67 +++++++++++++++++-------------
1 file changed, 37 insertions(+), 30 deletions(-)
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 9da6f8a..789aafe 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -229,6 +229,43 @@ static void __init print_memory_map(void)
}
/*
+ * Parse "mem=size@start" parameter rewriting a defined memory map
+ * We look for mem=size@start, where start and size are "value[KkMm]"
+ */
+static int __init early_parse_mem(char *p)
+{
+ static int usermem;
+ phys_addr_t start, size;
+
+ start = PHYS_OFFSET;
+ size = memparse(p, &p);
+ if (*p == '@')
+ start = memparse(p + 1, &p);
+
+ /*
+ * If a user specifies memory size, we blow away any automatically
+ * generated regions.
+ */
+ if (usermem == 0) {
+ phys_addr_t ram_start = memblock_start_of_DRAM();
+ phys_addr_t ram_end = memblock_end_of_DRAM() - ram_start;
+
+ pr_notice("Discard memory layout %pa - %pa",
+ &ram_start, &ram_end);
+
+ memblock_remove(ram_start, ram_end - ram_start);
+ boot_mem_map.nr_map = 0;
+ usermem = 1;
+ }
+ pr_notice("Add userdefined memory region %08zx @ %pa",
+ (size_t)size, &start);
+
+ add_memory_region(start, size, BOOT_MEM_RAM);
+ return 0;
+}
+early_param("mem", early_parse_mem);
+
+/*
* Manage initrd
*/
#ifdef CONFIG_BLK_DEV_INITRD
@@ -613,31 +650,6 @@ static void __init bootmem_init(void)
* initialization hook for anything else was introduced.
*/
-static int usermem __initdata;
-
-static int __init early_parse_mem(char *p)
-{
- phys_addr_t start, size;
-
- /*
- * If a user specifies memory size, we
- * blow away any automatically generated
- * size.
- */
- if (usermem == 0) {
- boot_mem_map.nr_map = 0;
- usermem = 1;
- }
- start = 0;
- size = memparse(p, &p);
- if (*p == '@')
- start = memparse(p + 1, &p);
-
- add_memory_region(start, size, BOOT_MEM_RAM);
- return 0;
-}
-early_param("mem", early_parse_mem);
-
#ifdef CONFIG_PROC_VMCORE
unsigned long setup_elfcorehdr, setup_elfcorehdr_size;
static int __init early_parse_elfcorehdr(char *p)
@@ -797,11 +809,6 @@ static void __init arch_mem_init(char **cmdline_p)
parse_early_param();
- if (usermem) {
- pr_info("User-defined physical RAM map:\n");
- print_memory_map();
- }
-
bootmem_init();
#ifdef CONFIG_PROC_VMCORE
if (setup_elfcorehdr && setup_elfcorehdr_size) {
--
2.6.6
^ permalink raw reply related
* [PATCH 05/21] MIPS memblock: Alter initrd memory reservation method
From: Serge Semin @ 2016-12-19 2:07 UTC (permalink / raw)
To: ralf, paul.burton, rabinv, matt.redfearn, james.hogan,
alexander.sverdlin, robh+dt, frowand.list
Cc: Sergey.Semin, linux-mips, devicetree, linux-kernel, Serge Semin
In-Reply-To: <1482113266-13207-1-git-send-email-fancer.lancer@gmail.com>
Since memblock is used, initrd memory region can be easily
verified and reserved if looks ok. Verification method will be
useful for other reservation methods.
Signed-off-by: Serge Semin <fancer.lancer@gmail.com>
---
arch/mips/kernel/setup.c | 157 ++++++++++++++++-------------
1 file changed, 87 insertions(+), 70 deletions(-)
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 789aafe..d2f38ac 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -82,6 +82,8 @@ static struct resource data_resource = { .name = "Kernel data", };
static void *detect_magic __initdata = detect_memory_region;
+static phys_addr_t __initdata mips_lowmem_limit;
+
/*
* General method to add RAM regions to the system
*
@@ -266,6 +268,38 @@ static int __init early_parse_mem(char *p)
early_param("mem", early_parse_mem);
/*
+ * Helper method checking whether passed lowmem region is valid
+ */
+static bool __init is_lowmem_and_valid(const char *name, phys_addr_t base,
+ phys_addr_t size)
+{
+ phys_addr_t end = base + size;
+
+ /* Check whether region belongs to actual memory */
+ if (!memblock_is_region_memory(base, size)) {
+ pr_err("%s %08zx @ %pa is not a memory region", name,
+ (size_t)size, &base);
+ return false;
+ }
+
+ /* Check whether region belongs to low memory */
+ if (end > mips_lowmem_limit) {
+ pr_err("%s %08zx @ %pa is out of low memory", name,
+ (size_t)size, &base);
+ return false;
+ }
+
+ /* Check whether region is free */
+ if (memblock_is_region_reserved(base, size)) {
+ pr_err("%s %08zx @ %pa overlaps in-use memory", name,
+ (size_t)size, &base);
+ return false;
+ }
+
+ return true;
+}
+
+/*
* Manage initrd
*/
#ifdef CONFIG_BLK_DEV_INITRD
@@ -292,47 +326,6 @@ static int __init rd_size_early(char *p)
}
early_param("rd_size", rd_size_early);
-/* it returns the next free pfn after initrd */
-static unsigned long __init init_initrd(void)
-{
- unsigned long end;
-
- /*
- * Board specific code or command line parser should have
- * already set up initrd_start and initrd_end. In these cases
- * perfom sanity checks and use them if all looks good.
- */
- if (!initrd_start || initrd_end <= initrd_start)
- goto disable;
-
- if (initrd_start & ~PAGE_MASK) {
- pr_err("initrd start must be page aligned\n");
- goto disable;
- }
- if (initrd_start < PAGE_OFFSET) {
- pr_err("initrd start < PAGE_OFFSET\n");
- goto disable;
- }
-
- /*
- * Sanitize initrd addresses. For example firmware
- * can't guess if they need to pass them through
- * 64-bits values if the kernel has been built in pure
- * 32-bit. We need also to switch from KSEG0 to XKPHYS
- * addresses now, so the code can now safely use __pa().
- */
- end = __pa(initrd_end);
- initrd_end = (unsigned long)__va(end);
- initrd_start = (unsigned long)__va(__pa(initrd_start));
-
- ROOT_DEV = Root_RAM0;
- return PFN_UP(end);
-disable:
- initrd_start = 0;
- initrd_end = 0;
- return 0;
-}
-
/* In some conditions (e.g. big endian bootloader with a little endian
kernel), the initrd might appear byte swapped. Try to detect this and
byte swap it if needed. */
@@ -362,26 +355,64 @@ static void __init maybe_bswap_initrd(void)
#endif
}
-static void __init finalize_initrd(void)
+/*
+ * Check and reserve memory occupied by initrd
+ */
+static void __init mips_reserve_initrd_mem(void)
{
- unsigned long size = initrd_end - initrd_start;
+ phys_addr_t phys_initrd_start, phys_initrd_end, phys_initrd_size;
- if (size == 0) {
- printk(KERN_INFO "Initrd not found or empty");
+ /*
+ * Board specific code or command line parser should have already set
+ * up initrd_start and initrd_end. In these cases perform sanity checks
+ * and use them if all looks good.
+ */
+ if (!initrd_start || initrd_end <= initrd_start) {
+ pr_info("No initrd found");
goto disable;
}
- if (__pa(initrd_end) > PFN_PHYS(max_low_pfn)) {
- printk(KERN_ERR "Initrd extends beyond end of memory");
+ if (initrd_start & ~PAGE_MASK) {
+ pr_err("Initrd start must be page aligned");
goto disable;
}
+ if (initrd_start < PAGE_OFFSET) {
+ pr_err("Initrd start < PAGE_OFFSET");
+ goto disable;
+ }
+
+ /*
+ * Sanitize initrd addresses. For example firmware can't guess if they
+ * need to pass them through 64-bits values if the kernel has been
+ * built in pure 32-bit. We need also to switch from KSEG0 to XKPHYS
+ * addresses now, so the code can now safely use __pa().
+ */
+ phys_initrd_start = __pa(initrd_start);
+ phys_initrd_end = __pa(initrd_end);
+ phys_initrd_size = phys_initrd_end - phys_initrd_start;
+ /* Check whether initrd region is within available lowmem and free */
+ if (!is_lowmem_and_valid("Initrd", phys_initrd_start, phys_initrd_size))
+ goto disable;
+
+ /* Initrd may be byteswapped in Octeon */
maybe_bswap_initrd();
- reserve_bootmem(__pa(initrd_start), size, BOOTMEM_DEFAULT);
+ /* Memory for initrd can be reserved now */
+ memblock_reserve(phys_initrd_start, phys_initrd_size);
+
+ /* Convert initrd to virtual addresses back (needed for x32 -> x64) */
+ initrd_start = (unsigned long)__va(phys_initrd_start);
+ initrd_end = (unsigned long)__va(phys_initrd_end);
+
+ /* It's OK to have initrd below actual memory start. Really? */
initrd_below_start_ok = 1;
- pr_info("Initial ramdisk at: 0x%lx (%lu bytes)\n",
- initrd_start, size);
+ pr_info("Initial ramdisk at: 0x%lx (%zu bytes)\n",
+ initrd_start, (size_t)phys_initrd_size);
+
+ /* Set root device to be first ram disk */
+ ROOT_DEV = Root_RAM0;
+
return;
disable:
printk(KERN_CONT " - disabling initrd\n");
@@ -391,12 +422,7 @@ disable:
#else /* !CONFIG_BLK_DEV_INITRD */
-static unsigned long __init init_initrd(void)
-{
- return 0;
-}
-
-#define finalize_initrd() do {} while (0)
+static void __init mips_reserve_initrd_mem(void) { }
#endif
@@ -408,8 +434,8 @@ static unsigned long __init init_initrd(void)
static void __init bootmem_init(void)
{
- init_initrd();
- finalize_initrd();
+ /* Check and reserve memory occupied by initrd */
+ mips_reserve_initrd_mem();
}
#else /* !CONFIG_SGI_IP27 */
@@ -421,13 +447,9 @@ static void __init bootmem_init(void)
unsigned long bootmap_size;
int i;
- /*
- * Sanity check any INITRD first. We don't take it into account
- * for bootmem setup initially, rely on the end-of-kernel-code
- * as our memory range starting point. Once bootmem is inited we
- * will reserve the area used for the initrd.
- */
- init_initrd();
+ /* Check and reserve memory occupied by initrd */
+ mips_reserve_initrd_mem();
+
reserved_end = (unsigned long) PFN_UP(__pa_symbol(&_end));
/*
@@ -618,11 +640,6 @@ static void __init bootmem_init(void)
#endif
}
#endif
-
- /*
- * Reserve initrd memory if needed.
- */
- finalize_initrd();
}
#endif /* CONFIG_SGI_IP27 */
--
2.6.6
^ permalink raw reply related
* [PATCH 06/21] MIPS memblock: Alter kexec-crashkernel parameters parser
From: Serge Semin @ 2016-12-19 2:07 UTC (permalink / raw)
To: ralf, paul.burton, rabinv, matt.redfearn, james.hogan,
alexander.sverdlin, robh+dt, frowand.list
Cc: Sergey.Semin, linux-mips, devicetree, linux-kernel, Serge Semin
In-Reply-To: <1482113266-13207-1-git-send-email-fancer.lancer@gmail.com>
Memblock API can be successfully used to verify whether crashkernel
memory region belongs to low memory, then it can be reserved within
memblock allocator.
Signed-off-by: Serge Semin <fancer.lancer@gmail.com>
---
arch/mips/kernel/setup.c | 105 ++++++++++++++---------------
1 file changed, 52 insertions(+), 53 deletions(-)
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index d2f38ac..cc6d06b 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -426,6 +426,55 @@ static void __init mips_reserve_initrd_mem(void) { }
#endif
+#ifdef CONFIG_KEXEC
+/*
+ * Parse passed crashkernel parameter and reserve corresponding memory
+ */
+static void __init mips_parse_crashkernel(void)
+{
+ unsigned long long total_mem;
+ unsigned long long crash_size, crash_base;
+ int ret;
+
+ /* Parse crachkernel parameter */
+ total_mem = memblock_phys_mem_size();
+ ret = parse_crashkernel(boot_command_line, total_mem,
+ &crash_size, &crash_base);
+ if (ret != 0 || crash_size <= 0)
+ return;
+
+ crashk_res.start = crash_base;
+ crashk_res.end = crash_base + crash_size - 1;
+
+ /* Check whether the region belogs to lowmem and valid */
+ if (!is_lowmem_and_valid("Crashkernel", crash_base, crash_size))
+ return;
+
+ /* Reserve crashkernel resource */
+ memblock_reserve(crash_base, crash_size);
+}
+
+/*
+ * Reserve crashkernel memory within passed RAM resource
+ */
+static void __init request_crashkernel(struct resource *res)
+{
+ int ret;
+
+ ret = request_resource(res, &crashk_res);
+ if (!ret)
+ pr_info("Reserving %ldMB of memory at %ldMB for crashkernel\n",
+ (unsigned long)((crashk_res.end -
+ crashk_res.start + 1) >> 20),
+ (unsigned long)(crashk_res.start >> 20));
+}
+#else /* !CONFIG_KEXEC */
+
+static void __init mips_parse_crashkernel(void) { }
+static void __init request_crashkernel(struct resource *res) { }
+
+#endif /* !CONFIG_KEXEC */
+
/*
* Initialize the bootmem allocator. It also setup initrd related data
* if needed.
@@ -450,6 +499,9 @@ static void __init bootmem_init(void)
/* Check and reserve memory occupied by initrd */
mips_reserve_initrd_mem();
+ /* Parse crashkernel parameter */
+ mips_parse_crashkernel();
+
reserved_end = (unsigned long) PFN_UP(__pa_symbol(&_end));
/*
@@ -717,52 +769,6 @@ static void __init arch_mem_addpart(phys_addr_t mem, phys_addr_t end, int type)
add_memory_region(mem, size, type);
}
-#ifdef CONFIG_KEXEC
-static inline unsigned long long get_total_mem(void)
-{
- unsigned long long total;
-
- total = max_pfn - min_low_pfn;
- return total << PAGE_SHIFT;
-}
-
-static void __init mips_parse_crashkernel(void)
-{
- unsigned long long total_mem;
- unsigned long long crash_size, crash_base;
- int ret;
-
- total_mem = get_total_mem();
- ret = parse_crashkernel(boot_command_line, total_mem,
- &crash_size, &crash_base);
- if (ret != 0 || crash_size <= 0)
- return;
-
- crashk_res.start = crash_base;
- crashk_res.end = crash_base + crash_size - 1;
-}
-
-static void __init request_crashkernel(struct resource *res)
-{
- int ret;
-
- ret = request_resource(res, &crashk_res);
- if (!ret)
- pr_info("Reserving %ldMB of memory at %ldMB for crashkernel\n",
- (unsigned long)((crashk_res.end -
- crashk_res.start + 1) >> 20),
- (unsigned long)(crashk_res.start >> 20));
-}
-#else /* !defined(CONFIG_KEXEC) */
-static void __init mips_parse_crashkernel(void)
-{
-}
-
-static void __init request_crashkernel(struct resource *res)
-{
-}
-#endif /* !defined(CONFIG_KEXEC) */
-
#define USE_PROM_CMDLINE IS_ENABLED(CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER)
#define USE_DTB_CMDLINE IS_ENABLED(CONFIG_MIPS_CMDLINE_FROM_DTB)
#define EXTEND_WITH_PROM IS_ENABLED(CONFIG_MIPS_CMDLINE_DTB_EXTEND)
@@ -836,13 +842,6 @@ static void __init arch_mem_init(char **cmdline_p)
}
#endif
- mips_parse_crashkernel();
-#ifdef CONFIG_KEXEC
- if (crashk_res.start != crashk_res.end)
- reserve_bootmem(crashk_res.start,
- crashk_res.end - crashk_res.start + 1,
- BOOTMEM_DEFAULT);
-#endif
device_tree_init();
sparse_init();
plat_swiotlb_setup();
--
2.6.6
^ permalink raw reply related
* [PATCH 07/21] MIPS memblock: Alter elfcorehdr parameters parser
From: Serge Semin @ 2016-12-19 2:07 UTC (permalink / raw)
To: ralf, paul.burton, rabinv, matt.redfearn, james.hogan,
alexander.sverdlin, robh+dt, frowand.list
Cc: Sergey.Semin, linux-mips, devicetree, linux-kernel, Serge Semin
In-Reply-To: <1482113266-13207-1-git-send-email-fancer.lancer@gmail.com>
Memblock API can be successfully used to verify whether elfcorehdr
memory region belongs to lowmemory, then it can be reserved within
memblock allocator. There is also available default method for
early parameters parser in kernel/crash_dump.c: setup_elfcorehdr(),
so it's wise to use one instead of creating our own doing actually
the same thing.
Signed-off-by: Serge Semin <fancer.lancer@gmail.com>
---
arch/mips/kernel/setup.c | 91 +++++++++++++++++-------------
1 file changed, 52 insertions(+), 39 deletions(-)
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index cc6d06b..52205fb 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -426,6 +426,55 @@ static void __init mips_reserve_initrd_mem(void) { }
#endif
+/*
+ * Reserve memory occupied by elfcorehdr
+ */
+static void __init mips_reserve_elfcorehdr(void)
+{
+#ifdef CONFIG_PROC_VMCORE
+ /*
+ * Don't reserve anything if kernel isn't booting after a panic and
+ * vmcore is usable (see linux/crash_dump.h for details)
+ */
+ if (!is_vmcore_usable())
+ return;
+
+ /* Check whether the passed address belongs to low memory */
+ if (elfcorehdr_addr + elfcorehdr_size >= mips_lowmem_limit) {
+ pr_err("Elfcorehdr %08zx @ %pa doesn't belong to low memory",
+ (size_t)elfcorehdr_size, &elfcorehdr_addr);
+ return;
+ }
+
+ /*
+ * If elfcorehdr_size hasn't been specified, then try to reserve upto
+ * low memory limit
+ */
+ if (!elfcorehdr_size)
+ elfcorehdr_size = mips_lowmem_limit - elfcorehdr_addr;
+
+ /* Check the region belongs to actual memory (size can be zero) */
+ if (!memblock_is_region_memory(elfcorehdr_addr, elfcorehdr_size)) {
+ pr_err("Elfcorehdr %08zx @ %pa is not a memory region",
+ (size_t)elfcorehdr_size, &elfcorehdr_addr);
+ return;
+ }
+
+ /* Check whether elfcorehdr region is free */
+ if (memblock_is_region_reserved(elfcorehdr_addr, elfcorehdr_size)) {
+ pr_err("Elfcorehdr %08zx @ %pa overlaps in-use memory",
+ (size_t)elfcorehdr_size, &elfcorehdr_addr);
+ return;
+ }
+
+ /* Reserve elfcorehdr within memblock */
+ memblock_reserve(elfcorehdr_addr, PAGE_ALIGN(elfcorehdr_size));
+
+ pr_info("Reserved memory for kdump at %08zx @ %pa\n",
+ (size_t)elfcorehdr_size, &elfcorehdr_addr);
+#endif /* CONFIG_PROC_VMCORE */
+}
+
#ifdef CONFIG_KEXEC
/*
* Parse passed crashkernel parameter and reserve corresponding memory
@@ -499,6 +548,9 @@ static void __init bootmem_init(void)
/* Check and reserve memory occupied by initrd */
mips_reserve_initrd_mem();
+ /* Reserve memory for elfcorehdr */
+ mips_reserve_elfcorehdr();
+
/* Parse crashkernel parameter */
mips_parse_crashkernel();
@@ -719,37 +771,6 @@ static void __init bootmem_init(void)
* initialization hook for anything else was introduced.
*/
-#ifdef CONFIG_PROC_VMCORE
-unsigned long setup_elfcorehdr, setup_elfcorehdr_size;
-static int __init early_parse_elfcorehdr(char *p)
-{
- int i;
-
- setup_elfcorehdr = memparse(p, &p);
-
- for (i = 0; i < boot_mem_map.nr_map; i++) {
- unsigned long start = boot_mem_map.map[i].addr;
- unsigned long end = (boot_mem_map.map[i].addr +
- boot_mem_map.map[i].size);
- if (setup_elfcorehdr >= start && setup_elfcorehdr < end) {
- /*
- * Reserve from the elf core header to the end of
- * the memory segment, that should all be kdump
- * reserved memory.
- */
- setup_elfcorehdr_size = end - setup_elfcorehdr;
- break;
- }
- }
- /*
- * If we don't find it in the memory map, then we shouldn't
- * have to worry about it, as the new kernel won't use it.
- */
- return 0;
-}
-early_param("elfcorehdr", early_parse_elfcorehdr);
-#endif
-
static void __init arch_mem_addpart(phys_addr_t mem, phys_addr_t end, int type)
{
phys_addr_t size;
@@ -833,14 +854,6 @@ static void __init arch_mem_init(char **cmdline_p)
parse_early_param();
bootmem_init();
-#ifdef CONFIG_PROC_VMCORE
- if (setup_elfcorehdr && setup_elfcorehdr_size) {
- printk(KERN_INFO "kdump reserved memory at %lx-%lx\n",
- setup_elfcorehdr, setup_elfcorehdr_size);
- reserve_bootmem(setup_elfcorehdr, setup_elfcorehdr_size,
- BOOTMEM_DEFAULT);
- }
-#endif
device_tree_init();
sparse_init();
--
2.6.6
^ permalink raw reply related
* [PATCH 08/21] MIPS memblock: Move kernel parameters parser into individual method
From: Serge Semin @ 2016-12-19 2:07 UTC (permalink / raw)
To: ralf, paul.burton, rabinv, matt.redfearn, james.hogan,
alexander.sverdlin, robh+dt, frowand.list
Cc: Sergey.Semin, linux-mips, devicetree, linux-kernel, Serge Semin
In-Reply-To: <1482113266-13207-1-git-send-email-fancer.lancer@gmail.com>
Main memory initialization method looks messy with cmd line parser
built-in. So it's better for readability to put it into a separated
method.
Signed-off-by: Serge Semin <fancer.lancer@gmail.com>
---
arch/mips/kernel/setup.c | 87 ++++++++++++++++--------------
1 file changed, 48 insertions(+), 39 deletions(-)
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 52205fb..9c1a60d 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -231,6 +231,51 @@ static void __init print_memory_map(void)
}
/*
+ * Parse passed cmdline
+ */
+#define USE_PROM_CMDLINE IS_ENABLED(CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER)
+#define USE_DTB_CMDLINE IS_ENABLED(CONFIG_MIPS_CMDLINE_FROM_DTB)
+#define EXTEND_WITH_PROM IS_ENABLED(CONFIG_MIPS_CMDLINE_EXTEND)
+#define BUILTIN_EXTEND_WITH_PROM \
+ IS_ENABLED(CONFIG_MIPS_CMDLINE_BUILTIN_EXTEND)
+
+static void __init mips_parse_param(char **cmdline_p)
+{
+#if defined(CONFIG_CMDLINE_BOOL) && defined(CONFIG_CMDLINE_OVERRIDE)
+ strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
+#else
+ if ((USE_PROM_CMDLINE && arcs_cmdline[0]) ||
+ (USE_DTB_CMDLINE && !boot_command_line[0]))
+ strlcpy(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE);
+
+ if (EXTEND_WITH_PROM && arcs_cmdline[0]) {
+ if (boot_command_line[0])
+ strlcat(boot_command_line, " ", COMMAND_LINE_SIZE);
+ strlcat(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE);
+ }
+
+#if defined(CONFIG_CMDLINE_BOOL)
+ if (builtin_cmdline[0]) {
+ if (boot_command_line[0])
+ strlcat(boot_command_line, " ", COMMAND_LINE_SIZE);
+ strlcat(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
+ }
+
+ if (BUILTIN_EXTEND_WITH_PROM && arcs_cmdline[0]) {
+ if (boot_command_line[0])
+ strlcat(boot_command_line, " ", COMMAND_LINE_SIZE);
+ strlcat(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE);
+ }
+#endif
+#endif
+ strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
+
+ *cmdline_p = command_line;
+
+ parse_early_param();
+}
+
+/*
* Parse "mem=size@start" parameter rewriting a defined memory map
* We look for mem=size@start, where start and size are "value[KkMm]"
*/
@@ -790,12 +835,6 @@ static void __init arch_mem_addpart(phys_addr_t mem, phys_addr_t end, int type)
add_memory_region(mem, size, type);
}
-#define USE_PROM_CMDLINE IS_ENABLED(CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER)
-#define USE_DTB_CMDLINE IS_ENABLED(CONFIG_MIPS_CMDLINE_FROM_DTB)
-#define EXTEND_WITH_PROM IS_ENABLED(CONFIG_MIPS_CMDLINE_DTB_EXTEND)
-#define BUILTIN_EXTEND_WITH_PROM \
- IS_ENABLED(CONFIG_MIPS_CMDLINE_BUILTIN_EXTEND)
-
static void __init arch_mem_init(char **cmdline_p)
{
struct memblock_region *reg;
@@ -804,6 +843,9 @@ static void __init arch_mem_init(char **cmdline_p)
/* call board setup routine */
plat_mem_setup();
+ /* Parse passed parameters */
+ mips_parse_param(cmdline_p);
+
/*
* Make sure all kernel memory is in the maps. The "UP" and
* "DOWN" are opposite for initdata since if it crosses over
@@ -820,39 +862,6 @@ static void __init arch_mem_init(char **cmdline_p)
pr_info("Determined physical RAM map:\n");
print_memory_map();
-#if defined(CONFIG_CMDLINE_BOOL) && defined(CONFIG_CMDLINE_OVERRIDE)
- strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
-#else
- if ((USE_PROM_CMDLINE && arcs_cmdline[0]) ||
- (USE_DTB_CMDLINE && !boot_command_line[0]))
- strlcpy(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE);
-
- if (EXTEND_WITH_PROM && arcs_cmdline[0]) {
- if (boot_command_line[0])
- strlcat(boot_command_line, " ", COMMAND_LINE_SIZE);
- strlcat(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE);
- }
-
-#if defined(CONFIG_CMDLINE_BOOL)
- if (builtin_cmdline[0]) {
- if (boot_command_line[0])
- strlcat(boot_command_line, " ", COMMAND_LINE_SIZE);
- strlcat(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
- }
-
- if (BUILTIN_EXTEND_WITH_PROM && arcs_cmdline[0]) {
- if (boot_command_line[0])
- strlcat(boot_command_line, " ", COMMAND_LINE_SIZE);
- strlcat(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE);
- }
-#endif
-#endif
- strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
-
- *cmdline_p = command_line;
-
- parse_early_param();
-
bootmem_init();
device_tree_init();
--
2.6.6
^ permalink raw reply related
* [PATCH 09/21] MIPS memblock: Move kernel memory reservation to individual method
From: Serge Semin @ 2016-12-19 2:07 UTC (permalink / raw)
To: ralf, paul.burton, rabinv, matt.redfearn, james.hogan,
alexander.sverdlin, robh+dt, frowand.list
Cc: Sergey.Semin, linux-mips, devicetree, linux-kernel, Serge Semin
In-Reply-To: <1482113266-13207-1-git-send-email-fancer.lancer@gmail.com>
The whole kernel text/data/bss must be reserved to prevent sudden
kernel crashes, for instance, due to unexpected non-zero default static
variables initializations.
Signed-off-by: Serge Semin <fancer.lancer@gmail.com>
---
arch/mips/kernel/setup.c | 117 +++++++++++++++--------------
1 file changed, 59 insertions(+), 58 deletions(-)
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 9c1a60d..e746793 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -472,6 +472,62 @@ static void __init mips_reserve_initrd_mem(void) { }
#endif
/*
+ * Reserve kernel code and data within memblock allocator
+ */
+static void __init mips_reserve_kernel_mem(void)
+{
+ phys_addr_t start, size;
+
+ /*
+ * Add kernel _text, _data, _bss, __init*, upto __end sections to
+ * boot_mem_map and memblock. We must reserve all of them!
+ */
+ start = __pa_symbol(&_text);
+ size = __pa_symbol(&_end) - start;
+ add_memory_region(start, size, BOOT_MEM_RAM);
+ /*
+ * It needs to be reserved within memblock as well. It's ok if memory
+ * has already been reserved with previous method
+ */
+ memblock_reserve(start, size);
+
+ /* Reserve nosave region for hibernation */
+ start = __pa_symbol(&__nosave_begin);
+ size = __pa_symbol(&__nosave_end) - start;
+ add_memory_region(start, size, BOOT_MEM_RAM);
+ memblock_reserve(start, size);
+
+ /* Initialize some init_mm fieldis. We may not need this? */
+ init_mm.start_code = (unsigned long)&_text;
+ init_mm.end_code = (unsigned long)&_etext;
+ init_mm.end_data = (unsigned long)&_edata;
+ init_mm.brk = (unsigned long)&_end;
+
+ /*
+ * The kernel reserves all memory below its _end symbol as bootmem,
+ * but the kernel may now be at a much higher address. The memory
+ * between the original and new locations may be returned to the system.
+ */
+#ifdef CONFIG_RELOCATABLE
+ if (__pa_symbol(&_text) > __pa_symbol(VMLINUX_LOAD_ADDRESS)) {
+ phys_addr_t offset;
+ extern void show_kernel_relocation(const char *level);
+
+ offset = __pa_symbol(_text) - __pa_symbol(VMLINUX_LOAD_ADDRESS);
+ memblock_free(__pa_symbol(VMLINUX_LOAD_ADDRESS), offset);
+
+#if defined(CONFIG_DEBUG_KERNEL) && defined(CONFIG_DEBUG_INFO)
+ /*
+ * This information is necessary when debugging the kernel
+ * But is a security vulnerability otherwise!
+ */
+ show_kernel_relocation(KERN_INFO);
+#endif
+ }
+#endif
+}
+
+/*
* Reserve memory occupied by elfcorehdr
*/
static void __init mips_reserve_elfcorehdr(void)
@@ -590,6 +646,9 @@ static void __init bootmem_init(void)
unsigned long bootmap_size;
int i;
+ /* Reserve kernel code/data memory */
+ mips_reserve_kernel_mem();
+
/* Check and reserve memory occupied by initrd */
mips_reserve_initrd_mem();
@@ -766,29 +825,6 @@ static void __init bootmem_init(void)
* Reserve the bootmap memory.
*/
reserve_bootmem(PFN_PHYS(mapstart), bootmap_size, BOOTMEM_DEFAULT);
-
-#ifdef CONFIG_RELOCATABLE
- /*
- * The kernel reserves all memory below its _end symbol as bootmem,
- * but the kernel may now be at a much higher address. The memory
- * between the original and new locations may be returned to the system.
- */
- if (__pa_symbol(_text) > __pa_symbol(VMLINUX_LOAD_ADDRESS)) {
- unsigned long offset;
- extern void show_kernel_relocation(const char *level);
-
- offset = __pa_symbol(_text) - __pa_symbol(VMLINUX_LOAD_ADDRESS);
- free_bootmem(__pa_symbol(VMLINUX_LOAD_ADDRESS), offset);
-
-#if defined(CONFIG_DEBUG_KERNEL) && defined(CONFIG_DEBUG_INFO)
- /*
- * This information is necessary when debugging the kernel
- * But is a security vulnerability otherwise!
- */
- show_kernel_relocation(KERN_INFO);
-#endif
- }
-#endif
}
#endif /* CONFIG_SGI_IP27 */
@@ -816,25 +852,6 @@ static void __init bootmem_init(void)
* initialization hook for anything else was introduced.
*/
-static void __init arch_mem_addpart(phys_addr_t mem, phys_addr_t end, int type)
-{
- phys_addr_t size;
- int i;
-
- size = end - mem;
- if (!size)
- return;
-
- /* Make sure it is in the boot_mem_map */
- for (i = 0; i < boot_mem_map.nr_map; i++) {
- if (mem >= boot_mem_map.map[i].addr &&
- mem < (boot_mem_map.map[i].addr +
- boot_mem_map.map[i].size))
- return;
- }
- add_memory_region(mem, size, type);
-}
-
static void __init arch_mem_init(char **cmdline_p)
{
struct memblock_region *reg;
@@ -846,19 +863,6 @@ static void __init arch_mem_init(char **cmdline_p)
/* Parse passed parameters */
mips_parse_param(cmdline_p);
- /*
- * Make sure all kernel memory is in the maps. The "UP" and
- * "DOWN" are opposite for initdata since if it crosses over
- * into another memory section you don't want that to be
- * freed when the initdata is freed.
- */
- arch_mem_addpart(PFN_DOWN(__pa_symbol(&_text)) << PAGE_SHIFT,
- PFN_UP(__pa_symbol(&_edata)) << PAGE_SHIFT,
- BOOT_MEM_RAM);
- arch_mem_addpart(PFN_UP(__pa_symbol(&__init_begin)) << PAGE_SHIFT,
- PFN_DOWN(__pa_symbol(&__init_end)) << PAGE_SHIFT,
- BOOT_MEM_INIT_RAM);
-
pr_info("Determined physical RAM map:\n");
print_memory_map();
@@ -873,9 +877,6 @@ static void __init arch_mem_init(char **cmdline_p)
for_each_memblock(reserved, reg)
if (reg->size != 0)
reserve_bootmem(reg->base, reg->size, BOOTMEM_DEFAULT);
-
- reserve_bootmem_region(__pa_symbol(&__nosave_begin),
- __pa_symbol(&__nosave_end)); /* Reserve for hibernation */
}
static void __init resource_init(void)
--
2.6.6
^ permalink raw reply related
* [PATCH 10/21] MIPS memblock: Discard bootmem allocator initialization
From: Serge Semin @ 2016-12-19 2:07 UTC (permalink / raw)
To: ralf, paul.burton, rabinv, matt.redfearn, james.hogan,
alexander.sverdlin, robh+dt, frowand.list
Cc: Sergey.Semin, linux-mips, devicetree, linux-kernel, Serge Semin
In-Reply-To: <1482113266-13207-1-git-send-email-fancer.lancer@gmail.com>
Bootmem allocator initialization needs to be discarded.
PFN limit constants are still in use by some subsystems, so they
need to be properly initialized. The initialization is moved into
a separate method and performed with help of commonly used
platform-specific constants. It might me too simplified, but most
of the kernel platforms do it the same way. Moreover it's much
easier to debug it, when it's not that complicated.
Signed-off-by: Serge Semin <fancer.lancer@gmail.com>
---
arch/mips/kernel/setup.c | 193 ++++-------------------------
1 file changed, 21 insertions(+), 172 deletions(-)
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index e746793..6562f55 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -626,6 +626,25 @@ static void __init request_crashkernel(struct resource *res) { }
#endif /* !CONFIG_KEXEC */
/*
+ * Calcualte PFN limits with respect to the defined memory layout
+ */
+static void __init find_pfn_limits(void)
+{
+ phys_addr_t ram_end = memblock_end_of_DRAM();
+
+ min_low_pfn = ARCH_PFN_OFFSET;
+ max_low_pfn = PFN_UP(HIGHMEM_START);
+ max_pfn = PFN_UP(ram_end);
+#ifdef CONFIG_HIGHMEM
+ highstart_pfn = max_low_pfn;
+ highend_pfn = max_pfn <= highstart_pfn ? highstart_pfn : max_pfn;
+#endif
+ pr_info("PFNs: low min %lu, low max %lu, high start %lu, high end %lu,"
+ "max %lu\n",
+ min_low_pfn, max_low_pfn, highstart_pfn, highend_pfn, max_pfn);
+}
+
+/*
* Initialize the bootmem allocator. It also setup initrd related data
* if needed.
*/
@@ -641,11 +660,6 @@ static void __init bootmem_init(void)
static void __init bootmem_init(void)
{
- unsigned long reserved_end;
- unsigned long mapstart = ~0UL;
- unsigned long bootmap_size;
- int i;
-
/* Reserve kernel code/data memory */
mips_reserve_kernel_mem();
@@ -658,173 +672,8 @@ static void __init bootmem_init(void)
/* Parse crashkernel parameter */
mips_parse_crashkernel();
- reserved_end = (unsigned long) PFN_UP(__pa_symbol(&_end));
-
- /*
- * max_low_pfn is not a number of pages. The number of pages
- * of the system is given by 'max_low_pfn - min_low_pfn'.
- */
- min_low_pfn = ~0UL;
- max_low_pfn = 0;
-
- /*
- * Find the highest page frame number we have available.
- */
- for (i = 0; i < boot_mem_map.nr_map; i++) {
- unsigned long start, end;
-
- if (boot_mem_map.map[i].type != BOOT_MEM_RAM)
- continue;
-
- start = PFN_UP(boot_mem_map.map[i].addr);
- end = PFN_DOWN(boot_mem_map.map[i].addr
- + boot_mem_map.map[i].size);
-
-#ifndef CONFIG_HIGHMEM
- /*
- * Skip highmem here so we get an accurate max_low_pfn if low
- * memory stops short of high memory.
- * If the region overlaps HIGHMEM_START, end is clipped so
- * max_pfn excludes the highmem portion.
- */
- if (start >= PFN_DOWN(HIGHMEM_START))
- continue;
- if (end > PFN_DOWN(HIGHMEM_START))
- end = PFN_DOWN(HIGHMEM_START);
-#endif
-
- if (end > max_low_pfn)
- max_low_pfn = end;
- if (start < min_low_pfn)
- min_low_pfn = start;
- if (end <= reserved_end)
- continue;
-#ifdef CONFIG_BLK_DEV_INITRD
- /* Skip zones before initrd and initrd itself */
- if (initrd_end && end <= (unsigned long)PFN_UP(__pa(initrd_end)))
- continue;
-#endif
- if (start >= mapstart)
- continue;
- mapstart = max(reserved_end, start);
- }
-
- if (min_low_pfn >= max_low_pfn)
- panic("Incorrect memory mapping !!!");
- if (min_low_pfn > ARCH_PFN_OFFSET) {
- pr_info("Wasting %lu bytes for tracking %lu unused pages\n",
- (min_low_pfn - ARCH_PFN_OFFSET) * sizeof(struct page),
- min_low_pfn - ARCH_PFN_OFFSET);
- } else if (min_low_pfn < ARCH_PFN_OFFSET) {
- pr_info("%lu free pages won't be used\n",
- ARCH_PFN_OFFSET - min_low_pfn);
- }
- min_low_pfn = ARCH_PFN_OFFSET;
-
- /*
- * Determine low and high memory ranges
- */
- max_pfn = max_low_pfn;
- if (max_low_pfn > PFN_DOWN(HIGHMEM_START)) {
-#ifdef CONFIG_HIGHMEM
- highstart_pfn = PFN_DOWN(HIGHMEM_START);
- highend_pfn = max_low_pfn;
-#endif
- max_low_pfn = PFN_DOWN(HIGHMEM_START);
- }
-
-#ifdef CONFIG_BLK_DEV_INITRD
- /*
- * mapstart should be after initrd_end
- */
- if (initrd_end)
- mapstart = max(mapstart, (unsigned long)PFN_UP(__pa(initrd_end)));
-#endif
-
- /*
- * Initialize the boot-time allocator with low memory only.
- */
- bootmap_size = init_bootmem_node(NODE_DATA(0), mapstart,
- min_low_pfn, max_low_pfn);
-
-
- for (i = 0; i < boot_mem_map.nr_map; i++) {
- unsigned long start, end;
-
- start = PFN_UP(boot_mem_map.map[i].addr);
- end = PFN_DOWN(boot_mem_map.map[i].addr
- + boot_mem_map.map[i].size);
-
- if (start <= min_low_pfn)
- start = min_low_pfn;
- if (start >= end)
- continue;
-
-#ifndef CONFIG_HIGHMEM
- if (end > max_low_pfn)
- end = max_low_pfn;
-
- /*
- * ... finally, is the area going away?
- */
- if (end <= start)
- continue;
-#endif
-
- memblock_add_node(PFN_PHYS(start), PFN_PHYS(end - start), 0);
- }
-
- /*
- * Register fully available low RAM pages with the bootmem allocator.
- */
- for (i = 0; i < boot_mem_map.nr_map; i++) {
- unsigned long start, end, size;
-
- start = PFN_UP(boot_mem_map.map[i].addr);
- end = PFN_DOWN(boot_mem_map.map[i].addr
- + boot_mem_map.map[i].size);
-
- /*
- * Reserve usable memory.
- */
- switch (boot_mem_map.map[i].type) {
- case BOOT_MEM_RAM:
- break;
- case BOOT_MEM_INIT_RAM:
- memory_present(0, start, end);
- continue;
- default:
- /* Not usable memory */
- continue;
- }
-
- /*
- * We are rounding up the start address of usable memory
- * and at the end of the usable range downwards.
- */
- if (start >= max_low_pfn)
- continue;
- if (start < reserved_end)
- start = reserved_end;
- if (end > max_low_pfn)
- end = max_low_pfn;
-
- /*
- * ... finally, is the area going away?
- */
- if (end <= start)
- continue;
- size = end - start;
-
- /* Register lowmem ranges */
- free_bootmem(PFN_PHYS(start), size << PAGE_SHIFT);
- memory_present(0, start, end);
- }
-
- /*
- * Reserve the bootmap memory.
- */
- reserve_bootmem(PFN_PHYS(mapstart), bootmap_size, BOOTMEM_DEFAULT);
+ /* Find memory PFN limits */
+ find_pfn_limits();
}
#endif /* CONFIG_SGI_IP27 */
--
2.6.6
^ permalink raw reply related
* [PATCH 11/21] MIPS memblock: Add memblock sanity check method
From: Serge Semin @ 2016-12-19 2:07 UTC (permalink / raw)
To: ralf, paul.burton, rabinv, matt.redfearn, james.hogan,
alexander.sverdlin, robh+dt, frowand.list
Cc: Sergey.Semin, linux-mips, devicetree, linux-kernel, Serge Semin
In-Reply-To: <1482113266-13207-1-git-send-email-fancer.lancer@gmail.com>
Perform memory sanity check right after basic memory is added.
It makes sure there is low memory available and there is no high
memory if one isn't supported. Additionally low memory limit needs
to be calculated so memblock would have a proper upper boundary for
memory allocations.
Signed-off-by: Serge Semin <fancer.lancer@gmail.com>
---
arch/mips/kernel/setup.c | 83 ++++++++++++++++++++++++++++++
1 file changed, 83 insertions(+)
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 6562f55..d2f410d 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -472,6 +472,86 @@ static void __init mips_reserve_initrd_mem(void) { }
#endif
/*
+ * Check initialized memory.
+ */
+static void __init sanity_check_meminfo(void)
+{
+ phys_addr_t physmem_start = PFN_PHYS(ARCH_PFN_OFFSET);
+ phys_addr_t size_limit = 0;
+ struct memblock_region *reg;
+ bool highmem = false;
+ bool should_use_highmem = false;
+
+ /*
+ * Walk over all memory ranges discarding highmem if it's disabled and
+ * calculating the memblock allocator limit
+ */
+ for_each_memblock(memory, reg) {
+ phys_addr_t block_start = reg->base;
+ phys_addr_t block_end = reg->base + reg->size;
+ phys_addr_t block_size = reg->size;
+
+ if (block_start >= HIGHMEM_START) {
+ highmem = true;
+ size_limit = block_size;
+ } else {
+ size_limit = HIGHMEM_START - block_start;
+ }
+
+ /* Discard highmem physical memory if it isn't supported */
+ if (!IS_BUILTIN(CONFIG_HIGHMEM)) {
+ /* Discard the whole highmem memory block */
+ if (highmem) {
+ pr_notice("Ignoring RAM at %pa-%pa (!CONFIG_HIGHMEM)\n",
+ &block_start, &block_end);
+ memblock_remove(block_start, block_size);
+ should_use_highmem = true;
+ continue;
+ }
+ /* Truncate memory block */
+ if (block_size > size_limit) {
+ phys_addr_t overlap_size = block_size - size_limit;
+ phys_addr_t highmem_start = HIGHMEM_START;
+
+ pr_notice("Truncate highmem %pa-%pa to -%pa\n",
+ &block_start, &block_end, &highmem_start);
+ memblock_remove(highmem_start, overlap_size);
+ block_end = highmem_start;
+ should_use_highmem = true;
+ }
+ }
+ /* Truncate region if it starts below ARCH_PFN_OFFSET */
+ if (block_start < physmem_start) {
+ phys_addr_t overlap_size = physmem_start - block_start;
+
+ pr_notice("Truncate lowmem %pa-%pa to %pa-\n",
+ &block_start, &block_end, &physmem_start);
+ memblock_remove(block_start, overlap_size);
+ }
+
+ /* Calculate actual lowmem limit for memblock allocator */
+ if (!highmem) {
+ if (block_end > mips_lowmem_limit) {
+ if (block_size > size_limit)
+ mips_lowmem_limit = HIGHMEM_START;
+ else
+ mips_lowmem_limit = block_end;
+ }
+ }
+ }
+
+ /* Panic if no lowmem has been determined */
+ if (!mips_lowmem_limit)
+ panic("Oops, where is low memory? 0_o\n");
+
+ if (should_use_highmem)
+ pr_notice("Consider using HIGHMEM enabled kernel\n");
+
+ /* Set memblock allocator limit */
+ memblock_set_current_limit(mips_lowmem_limit);
+}
+
+/*
* Reserve kernel code and data within memblock allocator
*/
static void __init mips_reserve_kernel_mem(void)
@@ -712,6 +792,9 @@ static void __init arch_mem_init(char **cmdline_p)
/* Parse passed parameters */
mips_parse_param(cmdline_p);
+ /* Sanity check the specified memory */
+ sanity_check_meminfo();
+
pr_info("Determined physical RAM map:\n");
print_memory_map();
--
2.6.6
^ permalink raw reply related
* [PATCH 12/21] MIPS memblock: Add memblock print outs in debug
From: Serge Semin @ 2016-12-19 2:07 UTC (permalink / raw)
To: ralf, paul.burton, rabinv, matt.redfearn, james.hogan,
alexander.sverdlin, robh+dt, frowand.list
Cc: Sergey.Semin, linux-mips, devicetree, linux-kernel, Serge Semin
In-Reply-To: <1482113266-13207-1-git-send-email-fancer.lancer@gmail.com>
When debugging it is useful to have a list of all memory regions
added and reserved in the system. Ones are printed right from
memblock if memblock_debug is enabled.
Signed-off-by: Serge Semin <fancer.lancer@gmail.com>
---
arch/mips/kernel/setup.c | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index d2f410d..409d23d 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -200,11 +200,16 @@ void __init detect_memory_region(phys_addr_t start, phys_addr_t sz_min, phys_add
add_memory_region(start, size, BOOT_MEM_RAM);
}
+/*
+ * Print declared memory layout
+ */
static void __init print_memory_map(void)
{
int i;
const int field = 2 * sizeof(unsigned long);
+ /* Print the added memory map */
+ pr_info("Determined physical RAM map:\n");
for (i = 0; i < boot_mem_map.nr_map; i++) {
printk(KERN_INFO " memory: %0*Lx @ %0*Lx ",
field, (unsigned long long) boot_mem_map.map[i].size,
@@ -228,6 +233,9 @@ static void __init print_memory_map(void)
break;
}
}
+
+ /* Print memblocks if memblock_debug is set */
+ memblock_dump_all();
}
/*
@@ -795,11 +803,11 @@ static void __init arch_mem_init(char **cmdline_p)
/* Sanity check the specified memory */
sanity_check_meminfo();
- pr_info("Determined physical RAM map:\n");
- print_memory_map();
-
bootmem_init();
+ /* Print memory map initialized by arch-specific code and params */
+ print_memory_map();
+
device_tree_init();
sparse_init();
plat_swiotlb_setup();
--
2.6.6
^ permalink raw reply related
* [PATCH 13/21] MIPS memblock: Add memblock allocator initialization
From: Serge Semin @ 2016-12-19 2:07 UTC (permalink / raw)
To: ralf, paul.burton, rabinv, matt.redfearn, james.hogan,
alexander.sverdlin, robh+dt, frowand.list
Cc: Sergey.Semin, linux-mips, devicetree, linux-kernel, Serge Semin
In-Reply-To: <1482113266-13207-1-git-send-email-fancer.lancer@gmail.com>
Initialization is done by subsequent performing of the following
steps:
1) Call platform-specific call adding memory regions
2) Parse kernel parameters looking (they may change memory layout)
3) Check whether declared memory is in sane
4) Reserve memory for kernel, initrd, crashdump, fdt, devices and CMA
5) Find PFN limits of the memory regions
6) Allow memblocks resize
7) Perform basic paging subsystem initialization: nodes, zones, page
tables (if necessary), kernel mapping and so on.
Sparse sections initialization is moved into mem_init() method
Signed-off-by: Serge Semin <fancer.lancer@gmail.com>
---
arch/mips/kernel/setup.c | 93 +++++++++++++++++++++++-------
1 file changed, 71 insertions(+), 22 deletions(-)
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 409d23d..b18d38c 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -9,6 +9,7 @@
* Copyright (C) 1996 Stoned Elipot
* Copyright (C) 1999 Silicon Graphics, Inc.
* Copyright (C) 2000, 2001, 2002, 2007 Maciej W. Rozycki
+ * Copyright (C) 2016 T-platforms
*/
#include <linux/init.h>
#include <linux/ioport.h>
@@ -27,6 +28,7 @@
#include <linux/device.h>
#include <linux/dma-contiguous.h>
#include <linux/decompress/generic.h>
+#include <linux/of_fdt.h>
#include <asm/addrspace.h>
#include <asm/bootinfo.h>
@@ -733,20 +735,34 @@ static void __init find_pfn_limits(void)
}
/*
- * Initialize the bootmem allocator. It also setup initrd related data
- * if needed.
+ * Initialize the memblock allocator
*/
#if defined(CONFIG_SGI_IP27) || (defined(CONFIG_CPU_LOONGSON3) && defined(CONFIG_NUMA))
-static void __init bootmem_init(void)
+static void __init mips_bootmem_init(void)
{
+ /* Reserve kernel code/data memory */
+ mips_reserve_kernel_mem();
+
/* Check and reserve memory occupied by initrd */
mips_reserve_initrd_mem();
+
+ /* Reserve memory for elfcorehdr */
+ mips_reserve_elfcorehdr();
+
+ /* Parse crashkernel parameter */
+ mips_parse_crashkernel();
+
+ /* Reserve memory for DMA contiguous allocator */
+ dma_contiguous_reserve(mips_lowmem_limit);
+
+ /* Allow memblock resize from now */
+ memblock_allow_resize();
}
#else /* !CONFIG_SGI_IP27 */
-static void __init bootmem_init(void)
+static void __init mips_bootmem_init(void)
{
/* Reserve kernel code/data memory */
mips_reserve_kernel_mem();
@@ -760,8 +776,23 @@ static void __init bootmem_init(void)
/* Parse crashkernel parameter */
mips_parse_crashkernel();
+ /*
+ * Platform code usually copies fdt, but still lets reserve its memory
+ * in case if it doesn't
+ */
+ early_init_fdt_reserve_self();
+
+ /* Scan reserved-memory nodes of fdt */
+ early_init_fdt_scan_reserved_mem();
+
+ /* Reserve memory for DMA contiguous allocator */
+ dma_contiguous_reserve(mips_lowmem_limit);
+
/* Find memory PFN limits */
find_pfn_limits();
+
+ /* Allow memblock resize from now */
+ memblock_allow_resize();
}
#endif /* CONFIG_SGI_IP27 */
@@ -770,30 +801,51 @@ static void __init bootmem_init(void)
* arch_mem_init - initialize memory management subsystem
*
* o plat_mem_setup() detects the memory configuration and will record detected
- * memory areas using add_memory_region.
+ * memory areas using add_memory_region, which in addition preinitializes
+ * memblock ranges.
*
* At this stage the memory configuration of the system is known to the
* kernel but generic memory management system is still entirely uninitialized.
*
- * o bootmem_init()
- * o sparse_init()
- * o paging_init()
- * o dma_contiguous_reserve()
+ * o mips_parse_param() parses parameters passed to the kernel in accordance
+ * with CMDLINE configs.
+ * o sanity_check_meminfo() performs memory ranges sanity checks, for
+ * example, drop high mem regions if it's not supported, set memblock limit
+ * of low memory allocations
+ * o mips_bootmem_init() performs memblock further initializations,
+ * particularly reserve crucial regions, including kernel segments, initrd,
+ * elfcorehdrm, crashkernel, fdt, DMA contiguous allocator, set PFN-related
+ * global variables.
+ * o print_memory_map() prints initialized and verified memory map
+ * o device_tree_init() calls platform-specific method to perform some
+ * device tree related operations
+ * o plat_swiotlb_setup() - platform-specific SWIOTLB setup method
+ *
+ * Basic setup of page allocator is done in setup_arch():
+ * o paging_init() performs initialization of paging subsystem, in particular
+ * setup page tables (PGD, PMD, etc), kernel mapping, sparse memory segments
+ * if supported. It performs memory test if one is enabled. Finally it
+ * calculates memory zone limits and calls free_area_init_node()
+ * initializing pages memory maps, nodes, nodes free areas - basis of the
+ * buddy allocator.
*
* At this stage the bootmem allocator is ready to use.
*
* NOTE: historically plat_mem_setup did the entire platform initialization.
- * This was rather impractical because it meant plat_mem_setup had to
+ * This was rather impractical because it meant plat_mem_setup had to
* get away without any kind of memory allocator. To keep old code from
* breaking plat_setup was just renamed to plat_mem_setup and a second platform
* initialization hook for anything else was introduced.
+ * Additionally boot_mem_map structure used to keep base memory layout so
+ * then ancient bootmem allocator would be properly initialized. Since memblock
+ * allocator is used for early memory management now, the boot_mem_map is
+ * conserved just for compatibility.
+ */
+/*
+ * MIPS early memory manager setup
*/
-
static void __init arch_mem_init(char **cmdline_p)
{
- struct memblock_region *reg;
- extern void plat_mem_setup(void);
-
/* call board setup routine */
plat_mem_setup();
@@ -803,20 +855,17 @@ static void __init arch_mem_init(char **cmdline_p)
/* Sanity check the specified memory */
sanity_check_meminfo();
- bootmem_init();
+ /* Initialize memblock allocator */
+ mips_bootmem_init();
/* Print memory map initialized by arch-specific code and params */
print_memory_map();
+ /* Perform platform-specific device tree scanning */
device_tree_init();
- sparse_init();
- plat_swiotlb_setup();
- dma_contiguous_reserve(PFN_PHYS(max_low_pfn));
- /* Tell bootmem about cma reserved memblock section */
- for_each_memblock(reserved, reg)
- if (reg->size != 0)
- reserve_bootmem(reg->base, reg->size, BOOTMEM_DEFAULT);
+ /* Perform platform-specific SWIOTLB setup */
+ plat_swiotlb_setup();
}
static void __init resource_init(void)
--
2.6.6
^ permalink raw reply related
* [PATCH 14/21] MIPS memblock: Alter IO resources initialization method
From: Serge Semin @ 2016-12-19 2:07 UTC (permalink / raw)
To: ralf, paul.burton, rabinv, matt.redfearn, james.hogan,
alexander.sverdlin, robh+dt, frowand.list
Cc: Sergey.Semin, linux-mips, devicetree, linux-kernel, Serge Semin
In-Reply-To: <1482113266-13207-1-git-send-email-fancer.lancer@gmail.com>
Replace resource initialization method with one using memblocks.
It fully reflects all available system RAM within memory regions.
Signed-off-by: Serge Semin <fancer.lancer@gmail.com>
---
arch/mips/kernel/setup.c | 40 +++++++++---------------------
1 file changed, 12 insertions(+), 28 deletions(-)
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index b18d38c..8bef2d3 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -868,46 +868,30 @@ static void __init arch_mem_init(char **cmdline_p)
plat_swiotlb_setup();
}
+/*
+ * Declare memory within system resources
+ */
static void __init resource_init(void)
{
- int i;
+ struct memblock_region *reg;
if (UNCAC_BASE != IO_BASE)
return;
+ /* Kernel code and data need to be registered within proper regions */
code_resource.start = __pa_symbol(&_text);
code_resource.end = __pa_symbol(&_etext) - 1;
data_resource.start = __pa_symbol(&_etext);
data_resource.end = __pa_symbol(&_edata) - 1;
- for (i = 0; i < boot_mem_map.nr_map; i++) {
+ /* Register RAM resources */
+ for_each_memblock(memory, reg) {
struct resource *res;
- unsigned long start, end;
-
- start = boot_mem_map.map[i].addr;
- end = boot_mem_map.map[i].addr + boot_mem_map.map[i].size - 1;
- if (start >= HIGHMEM_START)
- continue;
- if (end >= HIGHMEM_START)
- end = HIGHMEM_START - 1;
-
- res = alloc_bootmem(sizeof(struct resource));
-
- res->start = start;
- res->end = end;
- res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
-
- switch (boot_mem_map.map[i].type) {
- case BOOT_MEM_RAM:
- case BOOT_MEM_INIT_RAM:
- case BOOT_MEM_ROM_DATA:
- res->name = "System RAM";
- res->flags |= IORESOURCE_SYSRAM;
- break;
- case BOOT_MEM_RESERVED:
- default:
- res->name = "reserved";
- }
+ res = memblock_virt_alloc(sizeof(*res), 0);
+ res->name = "System RAM";
+ res->start = PFN_PHYS(memblock_region_memory_base_pfn(reg));
+ res->end = PFN_PHYS(memblock_region_memory_end_pfn(reg)) - 1;
+ res->flags = IORESOURCE_BUSY | IORESOURCE_SYSTEM_RAM;
request_resource(&iomem_resource, res);
--
2.6.6
^ permalink raw reply related
* [PATCH 15/21] MIPS memblock: Alter weakened MAAR initialization method
From: Serge Semin @ 2016-12-19 2:07 UTC (permalink / raw)
To: ralf, paul.burton, rabinv, matt.redfearn, james.hogan,
alexander.sverdlin, robh+dt, frowand.list
Cc: Sergey.Semin, linux-mips, devicetree, linux-kernel, Serge Semin
In-Reply-To: <1482113266-13207-1-git-send-email-fancer.lancer@gmail.com>
MAAR initialization method can be slightly simplified, since
memblock allocator is fully available.
Signed-off-by: Serge Semin <fancer.lancer@gmail.com>
---
arch/mips/mm/init.c | 27 +++++++++++++--------------
1 file changed, 13 insertions(+), 14 deletions(-)
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
index a4f49c7..49db909 100644
--- a/arch/mips/mm/init.c
+++ b/arch/mips/mm/init.c
@@ -22,6 +22,7 @@
#include <linux/ptrace.h>
#include <linux/mman.h>
#include <linux/mm.h>
+#include <linux/memblock.h>
#include <linux/bootmem.h>
#include <linux/highmem.h>
#include <linux/swap.h>
@@ -245,28 +246,26 @@ void __init fixrange_init(unsigned long start, unsigned long end,
#endif
}
-unsigned __weak platform_maar_init(unsigned num_pairs)
+/*
+ * Platform-specific method of MAAR registers initialization
+ */
+unsigned int __weak platform_maar_init(unsigned int num_pairs)
{
struct maar_config cfg[BOOT_MEM_MAP_MAX];
- unsigned i, num_configured, num_cfg = 0;
+ struct memblock_region *reg;
+ unsigned int num_configured, num_cfg = 0;
- for (i = 0; i < boot_mem_map.nr_map; i++) {
- switch (boot_mem_map.map[i].type) {
- case BOOT_MEM_RAM:
- case BOOT_MEM_INIT_RAM:
+ /* Collect RAM regions within MAAR config array */
+ for_each_memblock(memory, reg) {
+ if (num_cfg >= BOOT_MEM_MAP_MAX) {
+ pr_info("Too many memory regions to init MAARs");
break;
- default:
- continue;
}
-
/* Round lower up */
- cfg[num_cfg].lower = boot_mem_map.map[i].addr;
- cfg[num_cfg].lower = (cfg[num_cfg].lower + 0xffff) & ~0xffff;
+ cfg[num_cfg].lower = (reg->base + 0xffff) & ~0xffff;
/* Round upper down */
- cfg[num_cfg].upper = boot_mem_map.map[i].addr +
- boot_mem_map.map[i].size;
- cfg[num_cfg].upper = (cfg[num_cfg].upper & ~0xffff) - 1;
+ cfg[num_cfg].upper = ((reg->base + reg->size) & ~0xffff) - 1;
cfg[num_cfg].attrs = MIPS_MAAR_S;
num_cfg++;
--
2.6.6
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox