build/patch/kernel/rk322x-current/01-linux-1000-rockchip-soc-from-list.patch
paolo 9080d453e0 Moving rk322x-current to linux 5.9.y
Removed default-sample-phase property for base rk322x-box device tree
Enabled spdif out for rk322x-current and -dev flavours
Removed reserved node in device tree, u-boot v2020.10 and OPTEE autoconfigure reserved zones automatically
2020-11-13 19:40:52 +00:00

3713 lines
123 KiB
Diff

From faf0035972ca91afdf899bd9e5150b6a1e91bf8a Mon Sep 17 00:00:00 2001
From: Yifeng Zhao <yifeng.zhao@rock-chips.com>
Date: Wed, 28 Oct 2020 17:53:23 +0800
Subject: [PATCH] dt-bindings: mtd: Describe Rockchip RK3xxx NAND flash
controller
Documentation support for Rockchip RK3xxx NAND flash controllers
Signed-off-by: Yifeng Zhao <yifeng.zhao@rock-chips.com>
---
.../mtd/rockchip,nand-controller.yaml | 161 ++++++++++++++++++
1 file changed, 161 insertions(+)
create mode 100644 Documentation/devicetree/bindings/mtd/rockchip,nand-controller.yaml
diff --git a/Documentation/devicetree/bindings/mtd/rockchip,nand-controller.yaml b/Documentation/devicetree/bindings/mtd/rockchip,nand-controller.yaml
new file mode 100644
index 000000000000..0922536b1811
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/rockchip,nand-controller.yaml
@@ -0,0 +1,161 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mtd/rockchip,nand-controller.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Rockchip SoCs NAND FLASH Controller (NFC)
+
+allOf:
+ - $ref: "nand-controller.yaml#"
+
+maintainers:
+ - Heiko Stuebner <heiko@sntech.de>
+
+properties:
+ compatible:
+ oneOf:
+ - const: rockchip,px30-nfc
+ - const: rockchip,rk2928-nfc
+ - const: rockchip,rv1108-nfc
+ - items:
+ - const: rockchip,rk3036-nfc
+ - const: rockchip,rk2928-nfc
+ - items:
+ - const: rockchip,rk3308-nfc
+ - const: rockchip,rv1108-nfc
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ clocks:
+ minItems: 1
+ items:
+ - description: Bus Clock
+ - description: Module Clock
+
+ clock-names:
+ minItems: 1
+ items:
+ - const: ahb
+ - const: nfc
+
+ assigned-clocks:
+ maxItems: 1
+
+ assigned-clock-rates:
+ maxItems: 1
+
+ power-domains:
+ maxItems: 1
+
+patternProperties:
+ "^nand@[0-7]$":
+ type: object
+ properties:
+ reg:
+ minimum: 0
+ maximum: 7
+
+ nand-ecc-mode:
+ const: hw
+
+ nand-ecc-step-size:
+ const: 1024
+
+ nand-ecc-strength:
+ enum: [16, 24, 40, 60, 70]
+ description: |
+ The ECC configurations that can be supported are as follows.
+ NFC v600 ECC 16, 24, 40, 60
+ RK2928, RK3066, RK3188
+
+ NFC v622 ECC 16, 24, 40, 60
+ RK3036, RK3128
+
+ NFC v800 ECC 16
+ RK3308, RV1108
+
+ NFC v900 ECC 16, 40, 60, 70
+ RK3326, PX30
+
+ nand-bus-width:
+ const: 8
+
+ rockchip,boot-blks:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 2
+ default: 16
+ description:
+ The NFC driver need this information to select ECC
+ algorithms supported by the boot ROM.
+ Only used in combination with 'nand-is-boot-medium'.
+
+ rockchip,boot-ecc-strength:
+ enum: [16, 24, 40, 60, 70]
+ allOf:
+ - $ref: /schemas/types.yaml#/definitions/uint32
+ description: |
+ If specified it indicates that a different BCH/ECC setting is
+ supported by the boot ROM.
+ NFC v600 ECC 16, 24
+ RK2928, RK3066, RK3188
+
+ NFC v622 ECC 16, 24, 40, 60
+ RK3036, RK3128
+
+ NFC v800 ECC 16
+ RK3308, RV1108
+
+ NFC v900 ECC 16, 70
+ RK3326, PX30
+
+ Only used in combination with 'nand-is-boot-medium'.
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - clocks
+ - clock-names
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/rk3308-cru.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ nfc: nand-controller@ff4b0000 {
+ compatible = "rockchip,rk3308-nfc",
+ "rockchip,rv1108-nfc";
+ reg = <0xff4b0000 0x4000>;
+ interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cru HCLK_NANDC>, <&cru SCLK_NANDC>;
+ clock-names = "ahb", "nfc";
+ assigned-clocks = <&clks SCLK_NANDC>;
+ assigned-clock-rates = <150000000>;
+
+ pinctrl-0 = <&flash_ale &flash_bus8 &flash_cle &flash_csn0
+ &flash_rdn &flash_rdy &flash_wrn>;
+ pinctrl-names = "default";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ nand@0 {
+ reg = <0>;
+ label = "rk-nand";
+ nand-bus-width = <8>;
+ nand-ecc-mode = "hw";
+ nand-ecc-step-size = <1024>;
+ nand-ecc-strength = <16>;
+ nand-is-boot-medium;
+ rockchip,boot-blks = <8>;
+ rockchip,boot-ecc-strength = <16>;
+ };
+ };
+
+...
From f64fb6b73198e05bdd443330c56f67f32152604f Mon Sep 17 00:00:00 2001
From: Yifeng Zhao <yifeng.zhao@rock-chips.com>
Date: Wed, 28 Oct 2020 17:53:24 +0800
Subject: [PATCH] mtd: rawnand: rockchip: NFC drivers for RK3308, RK2928 and
others
This driver supports Rockchip NFC (NAND Flash Controller) found on RK3308,
RK2928, RKPX30, RV1108 and other SOCs. The driver has been tested using
8-bit NAND interface on the ARM based RK3308 platform.
Support Rockchip SoCs and NFC versions:
- PX30 and RK3326(NFCv900).
ECC: 16/40/60/70 bits/1KB.
CLOCK: ahb and nfc.
- RK3308 and RV1108(NFCv800).
ECC: 16 bits/1KB.
CLOCK: ahb and nfc.
- RK3036 and RK3128(NFCv622).
ECC: 16/24/40/60 bits/1KB.
CLOCK: ahb and nfc.
- RK3066, RK3188 and RK2928(NFCv600).
ECC: 16/24/40/60 bits/1KB.
CLOCK: ahb.
Supported features:
- Read full page data by DMA.
- Support HW ECC(one step is 1KB).
- Support 2 - 32K page size.
- Support 8 CS(depend on SoCs)
Limitations:
- No support for the ecc step size is 512.
- Untested on some SoCs.
- No support for subpages.
- No support for the builtin randomizer.
- The original bad block mask is not supported. It is recommended to use
the BBT(bad block table).
Signed-off-by: Yifeng Zhao <yifeng.zhao@rock-chips.com>
---
drivers/mtd/nand/raw/Kconfig | 12 +
drivers/mtd/nand/raw/Makefile | 1 +
.../mtd/nand/raw/rockchip-nand-controller.c | 1460 +++++++++++++++++
3 files changed, 1473 insertions(+)
create mode 100644 drivers/mtd/nand/raw/rockchip-nand-controller.c
diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig
index 1203775023ad..af0ed098ca0c 100644
--- a/drivers/mtd/nand/raw/Kconfig
+++ b/drivers/mtd/nand/raw/Kconfig
@@ -461,6 +461,18 @@ config MTD_NAND_ARASAN
Enables the driver for the Arasan NAND flash controller on
Zynq Ultrascale+ MPSoC.
+config MTD_NAND_ROCKCHIP
+ tristate "Rockchip NAND controller"
+ depends on ARCH_ROCKCHIP && HAS_IOMEM
+ help
+ Enables support for NAND controller on Rockchip SoCs.
+ There are four different versions of NAND FLASH Controllers,
+ including:
+ NFC v600: RK2928, RK3066, RK3188
+ NFC v622: RK3036, RK3128
+ NFC v800: RK3308, RV1108
+ NFC v900: PX30, RK3326
+
comment "Misc"
config MTD_SM_COMMON
diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile
index 2930f5b9015d..960c9be25204 100644
--- a/drivers/mtd/nand/raw/Makefile
+++ b/drivers/mtd/nand/raw/Makefile
@@ -58,6 +58,7 @@ obj-$(CONFIG_MTD_NAND_STM32_FMC2) += stm32_fmc2_nand.o
obj-$(CONFIG_MTD_NAND_MESON) += meson_nand.o
obj-$(CONFIG_MTD_NAND_CADENCE) += cadence-nand-controller.o
obj-$(CONFIG_MTD_NAND_ARASAN) += arasan-nand-controller.o
+obj-$(CONFIG_MTD_NAND_ROCKCHIP) += rockchip-nand-controller.o
nand-objs := nand_base.o nand_legacy.o nand_bbt.o nand_timings.o nand_ids.o
nand-objs += nand_onfi.o
diff --git a/drivers/mtd/nand/raw/rockchip-nand-controller.c b/drivers/mtd/nand/raw/rockchip-nand-controller.c
new file mode 100644
index 000000000000..2e96fd314346
--- /dev/null
+++ b/drivers/mtd/nand/raw/rockchip-nand-controller.c
@@ -0,0 +1,1460 @@
+// SPDX-License-Identifier: GPL-2.0 OR MIT
+/*
+ * Rockchip NAND Flash controller driver.
+ * Copyright (C) 2020 Rockchip Inc.
+ * Author: Yifeng Zhao <yifeng.zhao@rock-chips.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/interrupt.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+/*
+ * NFC Page Data Layout:
+ * 1024 Bytes Data + 4Bytes sys data + 28Bytes~124Bytes ecc +
+ * 1024 Bytes Data + 4Bytes sys data + 28Bytes~124Bytes ecc +
+ * ......
+ * NAND Page Data Layout:
+ * 1024 * n Data + m Bytes oob
+ * Original Bad Block Mask Location:
+ * First byte of oob(spare).
+ * nand_chip->oob_poi data layout:
+ * 4Bytes sys data + .... + 4Bytes sys data + ecc data.
+ */
+
+/* NAND controller register definition */
+#define NFC_READ (0)
+#define NFC_WRITE (1)
+
+#define NFC_FMCTL (0x00)
+#define FMCTL_CE_SEL_M 0xFF
+#define FMCTL_CE_SEL(x) (1 << (x))
+#define FMCTL_WP BIT(8)
+#define FMCTL_RDY BIT(9)
+
+#define NFC_FMWAIT (0x04)
+#define FLCTL_RST BIT(0)
+#define FLCTL_WR (1) /* 0: read, 1: write */
+#define FLCTL_XFER_ST BIT(2)
+#define FLCTL_XFER_EN BIT(3)
+#define FLCTL_ACORRECT BIT(10) /* Auto correct error bits. */
+#define FLCTL_XFER_READY BIT(20)
+#define FLCTL_XFER_SECTOR (22)
+#define FLCTL_TOG_FIX BIT(29)
+
+#define BCHCTL_BANK_M (7 << 5)
+#define BCHCTL_BANK (5)
+
+#define DMA_ST BIT(0)
+#define DMA_WR (1) /* 0: write, 1: read */
+#define DMA_EN BIT(2)
+#define DMA_AHB_SIZE (3) /* 0: 1, 1: 2, 2: 4 */
+#define DMA_BURST_SIZE (6) /* 0: 1, 3: 4, 5: 8, 7: 16 */
+#define DMA_INC_NUM (9) /* 1 - 16 */
+
+#define ECC_ERR_CNT(x, e) ((((x) >> (e).low) & (e).low_mask) |\
+ (((x) >> (e).high) & (e).high_mask) << (e).low_bn)
+#define INT_DMA BIT(0)
+#define NFC_BANK (0x800)
+#define NFC_BANK_STEP (0x100)
+#define BANK_DATA (0x00)
+#define BANK_ADDR (0x04)
+#define BANK_CMD (0x08)
+#define NFC_SRAM0 (0x1000)
+#define NFC_SRAM1 (0x1400)
+#define NFC_SRAM_SIZE (0x400)
+#define NFC_TIMEOUT (500000)
+#define NFC_MAX_OOB_PER_STEP 128
+#define NFC_MIN_OOB_PER_STEP 64
+#define MAX_DATA_SIZE 0xFFFC
+#define MAX_ADDRESS_CYC 6
+#define NFC_ECC_MAX_MODES 4
+#define NFC_MAX_NSELS (8) /* Some Socs only have 1 or 2 CSs. */
+#define NFC_SYS_DATA_SIZE (4) /* 4 bytes sys data in oob pre 1024 data.*/
+#define RK_DEFAULT_CLOCK_RATE (150 * 1000 * 1000) /* 150 Mhz */
+#define ACCTIMING(csrw, rwpw, rwcs) ((csrw) << 12 | (rwpw) << 5 | (rwcs))
+
+enum nfc_type {
+ NFC_V6,
+ NFC_V8,
+ NFC_V9,
+};
+
+/**
+ * struct rk_ecc_cnt_status: represent a ecc status data.
+ * @err_flag_bit: error flag bit index at register.
+ * @low: ecc count low bit index at register.
+ * @low_mask: mask bit.
+ * @low_bn: ecc count low bit number.
+ * @high: ecc count high bit index at register.
+ * @high_mask: mask bit
+ */
+struct ecc_cnt_status {
+ u8 err_flag_bit;
+ u8 low;
+ u8 low_mask;
+ u8 low_bn;
+ u8 high;
+ u8 high_mask;
+};
+
+/*
+ * @type: nfc version
+ * @ecc_strengths: ecc strengths
+ * @ecc_cfgs: ecc config values
+ * @flctl_off: FLCTL register offset
+ * @bchctl_off: BCHCTL register offset
+ * @dma_data_buf_off: DMA_DATA_BUF register offset
+ * @dma_oob_buf_off: DMA_OOB_BUF register offset
+ * @dma_cfg_off: DMA_CFG register offset
+ * @dma_st_off: DMA_ST register offset
+ * @bch_st_off: BCG_ST register offset
+ * @randmz_off: RANDMZ register offset
+ * @int_en_off: interrupt enable register offset
+ * @int_clr_off: interrupt clean register offset
+ * @int_st_off: interrupt status register offset
+ * @oob0_off: oob0 register offset
+ * @oob1_off: oob1 register offset
+ * @ecc0: represent ECC0 status data
+ * @ecc1: represent ECC1 status data
+ */
+struct nfc_cfg {
+ enum nfc_type type;
+ u8 ecc_strengths[NFC_ECC_MAX_MODES];
+ u32 ecc_cfgs[NFC_ECC_MAX_MODES];
+ u32 flctl_off;
+ u32 bchctl_off;
+ u32 dma_cfg_off;
+ u32 dma_data_buf_off;
+ u32 dma_oob_buf_off;
+ u32 dma_st_off;
+ u32 bch_st_off;
+ u32 randmz_off;
+ u32 int_en_off;
+ u32 int_clr_off;
+ u32 int_st_off;
+ u32 oob0_off;
+ u32 oob1_off;
+ struct ecc_cnt_status ecc0;
+ struct ecc_cnt_status ecc1;
+};
+
+struct rk_nfc_nand_chip {
+ struct list_head node;
+ struct nand_chip chip;
+
+ u16 spare_per_sector;
+ u16 oob_buf_per_sector;
+ u16 boot_blks;
+ u16 boot_ecc;
+ u16 metadata_size;
+
+ u8 nsels;
+ u8 sels[0];
+ /* Nothing after this field. */
+};
+
+struct rk_nfc {
+ struct nand_controller controller;
+ const struct nfc_cfg *cfg;
+ struct device *dev;
+
+ struct clk *nfc_clk;
+ struct clk *ahb_clk;
+ void __iomem *regs;
+
+ u32 selected_bank;
+ u32 band_offset;
+ u32 cur_clk;
+
+ struct completion done;
+ struct list_head chips;
+
+ u8 *buffer;
+ u8 *page_buf;
+ u32 *oob_buf;
+ u32 buffer_size;
+ u32 oob_buf_size;
+
+ unsigned long assigned_cs;
+};
+
+static inline struct rk_nfc_nand_chip *rk_nfc_to_rknand(struct nand_chip *chip)
+{
+ return container_of(chip, struct rk_nfc_nand_chip, chip);
+}
+
+static inline u8 *rk_nfc_buf_to_data_ptr(struct nand_chip *chip, const u8 *p, int i)
+{
+ return (u8 *)p + i * chip->ecc.size;
+}
+
+static inline u8 *rk_nfc_buf_to_oob_ptr(struct nand_chip *chip, int i)
+{
+ u8 *poi;
+
+ poi = chip->oob_poi + i * NFC_SYS_DATA_SIZE;
+
+ return poi;
+}
+
+static inline u8 *rk_nfc_buf_to_oob_ecc_ptr(struct nand_chip *chip, int i)
+{
+ struct rk_nfc_nand_chip *rknand = rk_nfc_to_rknand(chip);
+ u8 *poi;
+
+ poi = chip->oob_poi + rknand->metadata_size +
+ chip->ecc.bytes * i;
+
+ return poi;
+}
+
+static inline int rk_nfc_data_len(struct nand_chip *chip)
+{
+ struct rk_nfc_nand_chip *rknand = rk_nfc_to_rknand(chip);
+
+ return chip->ecc.size + rknand->spare_per_sector;
+}
+
+static inline u8 *rk_nfc_data_ptr(struct nand_chip *chip, int i)
+{
+ struct rk_nfc *nfc = nand_get_controller_data(chip);
+
+ return nfc->buffer + i * rk_nfc_data_len(chip);
+}
+
+static inline u8 *rk_nfc_oob_ptr(struct nand_chip *chip, int i)
+{
+ struct rk_nfc *nfc = nand_get_controller_data(chip);
+
+ return nfc->buffer + i * rk_nfc_data_len(chip) + chip->ecc.size;
+}
+
+static void rk_nfc_select_chip(struct nand_chip *chip, int cs)
+{
+ struct rk_nfc *nfc = nand_get_controller_data(chip);
+ struct rk_nfc_nand_chip *rknand = rk_nfc_to_rknand(chip);
+ u32 val;
+
+ if (cs < 0) {
+ nfc->selected_bank = -1;
+ /* Deselect the currently selected target. */
+ val = readl_relaxed(nfc->regs + NFC_FMCTL);
+ val &= ~FMCTL_CE_SEL_M;
+ writel(val, nfc->regs + NFC_FMCTL);
+ return;
+ }
+
+ nfc->selected_bank = rknand->sels[cs];
+ nfc->band_offset = NFC_BANK + nfc->selected_bank * NFC_BANK_STEP;
+
+ val = readl_relaxed(nfc->regs + NFC_FMCTL);
+ val &= ~FMCTL_CE_SEL_M;
+ val |= FMCTL_CE_SEL(nfc->selected_bank);
+
+ writel(val, nfc->regs + NFC_FMCTL);
+}
+
+static inline int rk_nfc_wait_ioready(struct rk_nfc *nfc)
+{
+ int rc;
+ u32 val;
+
+ rc = readl_relaxed_poll_timeout(nfc->regs + NFC_FMCTL, val,
+ val & FMCTL_RDY, 10, NFC_TIMEOUT);
+
+ return rc;
+}
+
+static void rk_nfc_read_buf(struct rk_nfc *nfc, u8 *buf, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ buf[i] = readb_relaxed(nfc->regs + nfc->band_offset +
+ BANK_DATA);
+}
+
+static void rk_nfc_write_buf(struct rk_nfc *nfc, const u8 *buf, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ writeb(buf[i], nfc->regs + nfc->band_offset + BANK_DATA);
+}
+
+static int rk_nfc_cmd(struct nand_chip *chip,
+ const struct nand_subop *subop)
+{
+ struct rk_nfc *nfc = nand_get_controller_data(chip);
+ unsigned int i, j, remaining, start;
+ int reg_offset = nfc->band_offset;
+ u8 *inbuf = NULL;
+ const u8 *outbuf;
+ u32 cnt = 0;
+ int ret = 0;
+
+ for (i = 0; i < subop->ninstrs; i++) {
+ const struct nand_op_instr *instr = &subop->instrs[i];
+
+ switch (instr->type) {
+ case NAND_OP_CMD_INSTR:
+ writeb(instr->ctx.cmd.opcode,
+ nfc->regs + reg_offset + BANK_CMD);
+ break;
+
+ case NAND_OP_ADDR_INSTR:
+ remaining = nand_subop_get_num_addr_cyc(subop, i);
+ start = nand_subop_get_addr_start_off(subop, i);
+
+ for (j = 0; j < 8 && j + start < remaining; j++)
+ writeb(instr->ctx.addr.addrs[j + start],
+ nfc->regs + reg_offset + BANK_ADDR);
+ break;
+
+ case NAND_OP_DATA_IN_INSTR:
+ case NAND_OP_DATA_OUT_INSTR:
+ start = nand_subop_get_data_start_off(subop, i);
+ cnt = nand_subop_get_data_len(subop, i);
+
+ if (instr->type == NAND_OP_DATA_OUT_INSTR) {
+ outbuf = instr->ctx.data.buf.out + start;
+ rk_nfc_write_buf(nfc, outbuf, cnt);
+ } else {
+ inbuf = instr->ctx.data.buf.in + start;
+ rk_nfc_read_buf(nfc, inbuf, cnt);
+ }
+ break;
+
+ case NAND_OP_WAITRDY_INSTR:
+ if (rk_nfc_wait_ioready(nfc) < 0) {
+ ret = -ETIMEDOUT;
+ dev_err(nfc->dev, "IO not ready\n");
+ }
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static const struct nand_op_parser rk_nfc_op_parser = NAND_OP_PARSER(
+ NAND_OP_PARSER_PATTERN(
+ rk_nfc_cmd,
+ NAND_OP_PARSER_PAT_CMD_ELEM(true),
+ NAND_OP_PARSER_PAT_ADDR_ELEM(true, MAX_ADDRESS_CYC),
+ NAND_OP_PARSER_PAT_CMD_ELEM(true),
+ NAND_OP_PARSER_PAT_WAITRDY_ELEM(true),
+ NAND_OP_PARSER_PAT_DATA_IN_ELEM(true, MAX_DATA_SIZE)),
+ NAND_OP_PARSER_PATTERN(
+ rk_nfc_cmd,
+ NAND_OP_PARSER_PAT_CMD_ELEM(true),
+ NAND_OP_PARSER_PAT_ADDR_ELEM(true, MAX_ADDRESS_CYC),
+ NAND_OP_PARSER_PAT_DATA_OUT_ELEM(true, MAX_DATA_SIZE),
+ NAND_OP_PARSER_PAT_CMD_ELEM(true),
+ NAND_OP_PARSER_PAT_WAITRDY_ELEM(true)),
+);
+
+static int rk_nfc_exec_op(struct nand_chip *chip,
+ const struct nand_operation *op,
+ bool check_only)
+{
+ if (!check_only)
+ rk_nfc_select_chip(chip, op->cs);
+
+ return nand_op_parser_exec_op(chip, &rk_nfc_op_parser, op,
+ check_only);
+}
+
+static int rk_nfc_setup_data_interface(struct nand_chip *chip, int csline,
+ const struct nand_interface_config *conf)
+{
+ struct rk_nfc *nfc = nand_get_controller_data(chip);
+ const struct nand_sdr_timings *timings;
+ u32 rate, tc2rw, trwpw, trw2c;
+ u32 temp;
+
+ if (csline == NAND_DATA_IFACE_CHECK_ONLY)
+ return 0;
+
+ timings = nand_get_sdr_timings(conf);
+ if (IS_ERR(timings))
+ return -EOPNOTSUPP;
+
+ if (IS_ERR(nfc->nfc_clk))
+ rate = clk_get_rate(nfc->ahb_clk);
+ else
+ rate = clk_get_rate(nfc->nfc_clk);
+
+ /* Turn clock rate into kHz. */
+ rate /= 1000;
+
+ tc2rw = 1;
+ trw2c = 1;
+
+ trwpw = max(timings->tWC_min, timings->tRC_min) / 1000;
+ trwpw = DIV_ROUND_UP(trwpw * rate, 1000000);
+
+ temp = timings->tREA_max / 1000;
+ temp = DIV_ROUND_UP(temp * rate, 1000000);
+
+ if (trwpw < temp)
+ trwpw = temp;
+
+ /*
+ * ACCON: access timing control register
+ * -------------------------------------
+ * 31:18: reserved
+ * 17:12: csrw, clock cycles from the falling edge of CSn to the
+ * falling edge of RDn or WRn
+ * 11:11: reserved
+ * 10:05: rwpw, the width of RDn or WRn in processor clock cycles
+ * 04:00: rwcs, clock cycles from the rising edge of RDn or WRn to the
+ * rising edge of CSn
+ */
+ temp = ACCTIMING(tc2rw, trwpw, trw2c);
+ writel(temp, nfc->regs + NFC_FMWAIT);
+
+ return 0;
+}
+
+static int rk_nfc_hw_ecc_setup(struct nand_chip *chip,
+ struct nand_ecc_ctrl *ecc,
+ uint32_t strength)
+{
+ struct rk_nfc *nfc = nand_get_controller_data(chip);
+ u32 reg, i;
+
+ for (i = 0; i < NFC_ECC_MAX_MODES; i++) {
+ if (ecc->strength == nfc->cfg->ecc_strengths[i]) {
+ reg = nfc->cfg->ecc_cfgs[i];
+ break;
+ }
+ }
+
+ if (i >= NFC_ECC_MAX_MODES)
+ return -EINVAL;
+
+ writel(reg, nfc->regs + nfc->cfg->bchctl_off);
+
+ return 0;
+}
+
+static void rk_nfc_xfer_start(struct rk_nfc *nfc, u8 rw, u8 n_KB,
+ dma_addr_t dma_data, dma_addr_t dma_oob)
+{
+ u32 dma_reg, fl_reg, bch_reg;
+
+ dma_reg = DMA_ST | ((!rw) << DMA_WR) | DMA_EN | (2 << DMA_AHB_SIZE) |
+ (7 << DMA_BURST_SIZE) | (16 << DMA_INC_NUM);
+
+ fl_reg = (rw << FLCTL_WR) | FLCTL_XFER_EN | FLCTL_ACORRECT |
+ (n_KB << FLCTL_XFER_SECTOR) | FLCTL_TOG_FIX;
+
+ if (nfc->cfg->type == NFC_V6 || nfc->cfg->type == NFC_V8) {
+ bch_reg = readl_relaxed(nfc->regs + nfc->cfg->bchctl_off);
+ bch_reg = (bch_reg & (~BCHCTL_BANK_M)) |
+ (nfc->selected_bank << BCHCTL_BANK);
+ writel(bch_reg, nfc->regs + nfc->cfg->bchctl_off);
+ }
+
+ writel(dma_reg, nfc->regs + nfc->cfg->dma_cfg_off);
+ writel((u32)dma_data, nfc->regs + nfc->cfg->dma_data_buf_off);
+ writel((u32)dma_oob, nfc->regs + nfc->cfg->dma_oob_buf_off);
+ writel(fl_reg, nfc->regs + nfc->cfg->flctl_off);
+ fl_reg |= FLCTL_XFER_ST;
+ writel(fl_reg, nfc->regs + nfc->cfg->flctl_off);
+}
+
+static int rk_nfc_wait_for_xfer_done(struct rk_nfc *nfc)
+{
+ void __iomem *ptr;
+ int ret = 0;
+ u32 reg;
+
+ ptr = nfc->regs + nfc->cfg->flctl_off;
+
+ ret = readl_relaxed_poll_timeout(ptr, reg,
+ reg & FLCTL_XFER_READY,
+ 10, NFC_TIMEOUT);
+
+ return ret;
+}
+
+static int rk_nfc_write_page_raw(struct nand_chip *chip, const u8 *buf,
+ int oob_on, int page)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ struct rk_nfc *nfc = nand_get_controller_data(chip);
+ struct nand_ecc_ctrl *ecc = &chip->ecc;
+ int ret = 0;
+ u32 i;
+
+ if (!buf)
+ memset(nfc->buffer, 0xff, mtd->writesize + mtd->oobsize);
+
+ for (i = 0; i < ecc->steps; i++) {
+ /* Copy data to nfc buffer. */
+ if (buf)
+ memcpy(rk_nfc_data_ptr(chip, i),
+ rk_nfc_buf_to_data_ptr(chip, buf, i),
+ ecc->size);
+ /*
+ * The first four bytes of OOB are reserved for the
+ * boot ROM. In some debugging cases, such as with a
+ * read, erase and write back test these 4 bytes stored
+ * in OOB also need to be written back.
+ */
+ if (!i)
+ memcpy(rk_nfc_oob_ptr(chip, i),
+ rk_nfc_buf_to_oob_ptr(chip, ecc->steps - 1),
+ NFC_SYS_DATA_SIZE);
+ else
+ memcpy(rk_nfc_oob_ptr(chip, i),
+ rk_nfc_buf_to_oob_ptr(chip, i - 1),
+ NFC_SYS_DATA_SIZE);
+ /* Copy ECC data to the NFC buffer. */
+ memcpy(rk_nfc_oob_ptr(chip, i) + NFC_SYS_DATA_SIZE,
+ rk_nfc_buf_to_oob_ecc_ptr(chip, i),
+ ecc->bytes);
+ }
+
+ nand_prog_page_begin_op(chip, page, 0, NULL, 0);
+ rk_nfc_write_buf(nfc, buf, mtd->writesize + mtd->oobsize);
+ ret = nand_prog_page_end_op(chip);
+
+ /*
+ * Deselect the currently selected target after the ops is done
+ * to reduce the power consumption.
+ */
+ rk_nfc_select_chip(chip, -1);
+
+ return ret;
+}
+
+static int rk_nfc_write_oob(struct nand_chip *chip, int page)
+{
+ return rk_nfc_write_page_raw(chip, NULL, 1, page);
+}
+
+static int rk_nfc_write_page_hwecc(struct nand_chip *chip, const u8 *buf,
+ int oob_on, int page)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ struct rk_nfc *nfc = nand_get_controller_data(chip);
+ struct rk_nfc_nand_chip *rknand = rk_nfc_to_rknand(chip);
+ struct nand_ecc_ctrl *ecc = &chip->ecc;
+ int oob_step = (ecc->bytes > 60) ? NFC_MAX_OOB_PER_STEP :
+ NFC_MIN_OOB_PER_STEP;
+ int pages_per_blk = mtd->erasesize / mtd->writesize;
+ int ret = 0, i, boot_rom_mode = 0;
+ dma_addr_t dma_data, dma_oob;
+ u32 reg;
+ u8 *oob;
+
+ nand_prog_page_begin_op(chip, page, 0, NULL, 0);
+
+ memcpy(nfc->page_buf, buf, mtd->writesize);
+
+ /*
+ * The first blocks (4, 8 or 16 depending on the device) are used
+ * by the boot ROM and the first 32 bits of OOB need to link to
+ * the next page address in the same block. We can't directly copy
+ * OOB data from the MTD framework, because this page address
+ * conflicts for example with the bad block marker (BBM),
+ * so we shift all OOB data including the BBM with 4 byte positions.
+ * As a consequence the OOB size available to the MTD framework is
+ * also reduced with 4 bytes.
+ *
+ * PA0 PA1 PA2 PA3 | BBM OOB1 OOB2 OOB3 | ...
+ *
+ * If a NAND is not a boot medium or the page is not a boot block,
+ * the first 4 bytes are left untouched by writing 0xFF to them.
+ *
+ * 0xFF 0xFF 0xFF 0xFF | BBM OOB1 OOB2 OOB3 | ...
+ *
+ * Configure the ECC algorithm supported by the boot ROM.
+ */
+ if ((page < pages_per_blk * rknand->boot_blks) &&
+ (chip->options & NAND_IS_BOOT_MEDIUM)) {
+ boot_rom_mode = 1;
+ if (rknand->boot_ecc != ecc->strength)
+ rk_nfc_hw_ecc_setup(chip, ecc,
+ rknand->boot_ecc);
+ }
+
+ for (i = 0; i < ecc->steps; i++) {
+ if (!i) {
+ reg = 0xFFFFFFFF;
+ } else {
+ oob = chip->oob_poi + (i - 1) * NFC_SYS_DATA_SIZE;
+ reg = oob[0] | oob[1] << 8 | oob[2] << 16 |
+ oob[3] << 24;
+ }
+ if (!i && boot_rom_mode)
+ reg = (page & (pages_per_blk - 1)) * 4;
+
+ if (nfc->cfg->type == NFC_V9)
+ nfc->oob_buf[i] = reg;
+ else
+ nfc->oob_buf[i * (oob_step / 4)] = reg;
+ }
+
+ dma_data = dma_map_single(nfc->dev, (void *)nfc->page_buf,
+ mtd->writesize, DMA_TO_DEVICE);
+ dma_oob = dma_map_single(nfc->dev, nfc->oob_buf,
+ ecc->steps * oob_step,
+ DMA_TO_DEVICE);
+
+ reinit_completion(&nfc->done);
+ writel(INT_DMA, nfc->regs + nfc->cfg->int_en_off);
+
+ rk_nfc_xfer_start(nfc, NFC_WRITE, ecc->steps, dma_data,
+ dma_oob);
+ ret = wait_for_completion_timeout(&nfc->done,
+ msecs_to_jiffies(100));
+ if (!ret)
+ dev_warn(nfc->dev, "write: wait dma done timeout.\n");
+ /*
+ * Whether the DMA transfer is completed or not. The driver
+ * needs to check the NFC`s status register to see if the data
+ * transfer was completed.
+ */
+ ret = rk_nfc_wait_for_xfer_done(nfc);
+
+ dma_unmap_single(nfc->dev, dma_data, mtd->writesize,
+ DMA_TO_DEVICE);
+ dma_unmap_single(nfc->dev, dma_oob, ecc->steps * oob_step,
+ DMA_TO_DEVICE);
+
+ if (boot_rom_mode && rknand->boot_ecc != ecc->strength)
+ rk_nfc_hw_ecc_setup(chip, ecc, ecc->strength);
+
+ if (ret) {
+ ret = -EIO;
+ dev_err(nfc->dev,
+ "write: wait transfer done timeout.\n");
+ }
+
+ if (ret)
+ return ret;
+
+ ret = nand_prog_page_end_op(chip);
+
+ /*
+ * Deselect the currently selected target after the ops is done
+ * to reduce the power consumption.
+ */
+ rk_nfc_select_chip(chip, -1);
+
+ return ret;
+}
+
+static int rk_nfc_read_page_raw(struct nand_chip *chip, u8 *buf, int oob_on,
+ int page)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ struct rk_nfc *nfc = nand_get_controller_data(chip);
+ struct nand_ecc_ctrl *ecc = &chip->ecc;
+ int i;
+
+ nand_read_page_op(chip, page, 0, NULL, 0);
+ rk_nfc_read_buf(nfc, nfc->buffer, mtd->writesize + mtd->oobsize);
+
+ /*
+ * Deselect the currently selected target after the ops is done
+ * to reduce the power consumption.
+ */
+ rk_nfc_select_chip(chip, -1);
+
+ for (i = 0; i < ecc->steps; i++) {
+ /*
+ * The first four bytes of OOB are reserved for the
+ * boot ROM. In some debugging cases, such as with a read,
+ * erase and write back test, these 4 bytes also must be
+ * saved somewhere, otherwise this information will be
+ * lost during a write back.
+ */
+ if (!i)
+ memcpy(rk_nfc_buf_to_oob_ptr(chip, ecc->steps - 1),
+ rk_nfc_oob_ptr(chip, i),
+ NFC_SYS_DATA_SIZE);
+ else
+ memcpy(rk_nfc_buf_to_oob_ptr(chip, i - 1),
+ rk_nfc_oob_ptr(chip, i),
+ NFC_SYS_DATA_SIZE);
+ /* Copy ECC data from the NFC buffer. */
+ memcpy(rk_nfc_buf_to_oob_ecc_ptr(chip, i),
+ rk_nfc_oob_ptr(chip, i) + NFC_SYS_DATA_SIZE,
+ ecc->bytes);
+ /* Copy data from the NFC buffer. */
+ if (buf)
+ memcpy(rk_nfc_buf_to_data_ptr(chip, buf, i),
+ rk_nfc_data_ptr(chip, i),
+ ecc->size);
+ }
+
+ return 0;
+}
+
+static int rk_nfc_read_oob(struct nand_chip *chip, int page)
+{
+ return rk_nfc_read_page_raw(chip, NULL, 1, page);
+}
+
+static int rk_nfc_read_page_hwecc(struct nand_chip *chip, u8 *buf, int oob_on,
+ int page)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ struct rk_nfc *nfc = nand_get_controller_data(chip);
+ struct rk_nfc_nand_chip *rknand = rk_nfc_to_rknand(chip);
+ struct nand_ecc_ctrl *ecc = &chip->ecc;
+ int oob_step = (ecc->bytes > 60) ? NFC_MAX_OOB_PER_STEP :
+ NFC_MIN_OOB_PER_STEP;
+ int pages_per_blk = mtd->erasesize / mtd->writesize;
+ dma_addr_t dma_data, dma_oob;
+ int ret = 0, i, boot_rom_mode = 0;
+ int bitflips = 0, bch_st;
+ u8 *oob;
+ u32 tmp;
+
+ nand_read_page_op(chip, page, 0, NULL, 0);
+
+ dma_data = dma_map_single(nfc->dev, nfc->page_buf,
+ mtd->writesize,
+ DMA_FROM_DEVICE);
+ dma_oob = dma_map_single(nfc->dev, nfc->oob_buf,
+ ecc->steps * oob_step,
+ DMA_FROM_DEVICE);
+
+ /*
+ * The first blocks (4, 8 or 16 depending on the device)
+ * are used by the boot ROM.
+ * Configure the ECC algorithm supported by the boot ROM.
+ */
+ if ((page < pages_per_blk * rknand->boot_blks) &&
+ (chip->options & NAND_IS_BOOT_MEDIUM)) {
+ boot_rom_mode = 1;
+ if (rknand->boot_ecc != ecc->strength)
+ rk_nfc_hw_ecc_setup(chip, ecc,
+ rknand->boot_ecc);
+ }
+
+ reinit_completion(&nfc->done);
+ writel(INT_DMA, nfc->regs + nfc->cfg->int_en_off);
+ rk_nfc_xfer_start(nfc, NFC_READ, ecc->steps, dma_data,
+ dma_oob);
+ ret = wait_for_completion_timeout(&nfc->done,
+ msecs_to_jiffies(100));
+ if (!ret)
+ dev_warn(nfc->dev, "read: wait dma done timeout.\n");
+ /*
+ * Whether the DMA transfer is completed or not. The driver
+ * needs to check the NFC`s status register to see if the data
+ * transfer was completed.
+ */
+ ret = rk_nfc_wait_for_xfer_done(nfc);
+ dma_unmap_single(nfc->dev, dma_data, mtd->writesize,
+ DMA_FROM_DEVICE);
+ dma_unmap_single(nfc->dev, dma_oob, ecc->steps * oob_step,
+ DMA_FROM_DEVICE);
+
+ if (ret) {
+ bitflips = -EIO;
+ dev_err(nfc->dev,
+ "read: wait transfer done timeout.\n");
+ goto out;
+ }
+
+ for (i = 1; i < ecc->steps; i++) {
+ oob = chip->oob_poi + (i - 1) * NFC_SYS_DATA_SIZE;
+ if (nfc->cfg->type == NFC_V9)
+ tmp = nfc->oob_buf[i];
+ else
+ tmp = nfc->oob_buf[i * (oob_step / 4)];
+ *oob++ = (u8)tmp;
+ *oob++ = (u8)(tmp >> 8);
+ *oob++ = (u8)(tmp >> 16);
+ *oob++ = (u8)(tmp >> 24);
+ }
+
+ for (i = 0; i < (ecc->steps / 2); i++) {
+ bch_st = readl_relaxed(nfc->regs +
+ nfc->cfg->bch_st_off + i * 4);
+ if (bch_st & BIT(nfc->cfg->ecc0.err_flag_bit) ||
+ bch_st & BIT(nfc->cfg->ecc1.err_flag_bit)) {
+ mtd->ecc_stats.failed++;
+ bitflips = 0;
+ } else {
+ ret = ECC_ERR_CNT(bch_st, nfc->cfg->ecc0);
+ mtd->ecc_stats.corrected += ret;
+ bitflips = max_t(u32, bitflips, ret);
+
+ ret = ECC_ERR_CNT(bch_st, nfc->cfg->ecc1);
+ mtd->ecc_stats.corrected += ret;
+ bitflips = max_t(u32, bitflips, ret);
+ }
+ }
+out:
+ memcpy(buf, nfc->page_buf, mtd->writesize);
+
+ if (boot_rom_mode && rknand->boot_ecc != ecc->strength)
+ rk_nfc_hw_ecc_setup(chip, ecc, ecc->strength);
+
+ if (bitflips > ecc->strength)
+ dev_err(nfc->dev, "read page: %x ecc error!\n", page);
+
+ /*
+ * Deselect the currently selected target after the ops is done
+ * to reduce the power consumption.
+ */
+ rk_nfc_select_chip(chip, -1);
+
+ return bitflips;
+}
+
+static inline void rk_nfc_hw_init(struct rk_nfc *nfc)
+{
+ /* Disable flash wp. */
+ writel(FMCTL_WP, nfc->regs + NFC_FMCTL);
+ /* Config default timing 40ns at 150 Mhz nfc clock. */
+ writel(0x1081, nfc->regs + NFC_FMWAIT);
+ /* Disable randomizer and DMA. */
+ writel(0, nfc->regs + nfc->cfg->randmz_off);
+ writel(0, nfc->regs + nfc->cfg->dma_cfg_off);
+ writel(FLCTL_RST, nfc->regs + nfc->cfg->flctl_off);
+}
+
+static irqreturn_t rk_nfc_irq(int irq, void *id)
+{
+ struct rk_nfc *nfc = id;
+ u32 sta, ien;
+
+ sta = readl_relaxed(nfc->regs + nfc->cfg->int_st_off);
+ ien = readl_relaxed(nfc->regs + nfc->cfg->int_en_off);
+
+ if (!(sta & ien))
+ return IRQ_NONE;
+
+ writel(sta, nfc->regs + nfc->cfg->int_clr_off);
+ writel(~sta & ien, nfc->regs + nfc->cfg->int_en_off);
+
+ complete(&nfc->done);
+
+ return IRQ_HANDLED;
+}
+
+static int rk_nfc_enable_clks(struct device *dev, struct rk_nfc *nfc)
+{
+ int ret;
+
+ if (!IS_ERR(nfc->nfc_clk)) {
+ ret = clk_prepare_enable(nfc->nfc_clk);
+ if (ret) {
+ dev_err(dev, "failed to enable nfc clk\n");
+ return ret;
+ }
+ }
+
+ ret = clk_prepare_enable(nfc->ahb_clk);
+ if (ret) {
+ dev_err(dev, "failed to enable ahb clk\n");
+ if (!IS_ERR(nfc->nfc_clk))
+ clk_disable_unprepare(nfc->nfc_clk);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void rk_nfc_disable_clks(struct rk_nfc *nfc)
+{
+ if (!IS_ERR(nfc->nfc_clk))
+ clk_disable_unprepare(nfc->nfc_clk);
+ clk_disable_unprepare(nfc->ahb_clk);
+}
+
+static int rk_nfc_ooblayout_free(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *oob_region)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct rk_nfc_nand_chip *rknand = rk_nfc_to_rknand(chip);
+
+ if (section)
+ return -ERANGE;
+
+ /*
+ * The beginning of the OOB area stores the reserved data for the NFC,
+ * the size of the reserved data is NFC_SYS_DATA_SIZE bytes.
+ */
+ oob_region->length = rknand->metadata_size - NFC_SYS_DATA_SIZE - 2;
+ oob_region->offset = NFC_SYS_DATA_SIZE + 2;
+
+ return 0;
+}
+
+static int rk_nfc_ooblayout_ecc(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *oob_region)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct rk_nfc_nand_chip *rknand = rk_nfc_to_rknand(chip);
+
+ if (section)
+ return -ERANGE;
+
+ oob_region->length = mtd->oobsize - rknand->metadata_size;
+ oob_region->offset = rknand->metadata_size;
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops rk_nfc_ooblayout_ops = {
+ .free = rk_nfc_ooblayout_free,
+ .ecc = rk_nfc_ooblayout_ecc,
+};
+
+static int rk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct rk_nfc *nfc = nand_get_controller_data(chip);
+ struct nand_ecc_ctrl *ecc = &chip->ecc;
+ const u8 *strengths = nfc->cfg->ecc_strengths;
+ u8 max_strength, nfc_max_strength;
+ int i;
+
+ nfc_max_strength = nfc->cfg->ecc_strengths[0];
+ /* If optional dt settings not present. */
+ if (!ecc->size || !ecc->strength ||
+ ecc->strength > nfc_max_strength) {
+ chip->ecc.size = 1024;
+ ecc->steps = mtd->writesize / ecc->size;
+
+ /*
+ * HW ECC always requests the number of ECC bytes per 1024 byte
+ * blocks. The first 4 OOB bytes are reserved for sys data.
+ */
+ max_strength = ((mtd->oobsize / ecc->steps) - 4) * 8 /
+ fls(8 * 1024);
+ if (max_strength > nfc_max_strength)
+ max_strength = nfc_max_strength;
+
+ for (i = 0; i < 4; i++) {
+ if (max_strength >= strengths[i])
+ break;
+ }
+
+ if (i >= 4) {
+ dev_err(nfc->dev, "Unsupported ECC strength\n");
+ return -EOPNOTSUPP;
+ }
+
+ ecc->strength = strengths[i];
+ }
+ ecc->steps = mtd->writesize / ecc->size;
+ ecc->bytes = DIV_ROUND_UP(ecc->strength * fls(8 * 1024), 8);
+ /* HW ECC always work with even numbers of ECC bytes. */
+ ecc->bytes = ALIGN(ecc->bytes, 2);
+
+ rk_nfc_hw_ecc_setup(chip, ecc, ecc->strength);
+
+ return 0;
+}
+
+static int rk_nfc_attach_chip(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ struct device *dev = mtd->dev.parent;
+ struct rk_nfc *nfc = nand_get_controller_data(chip);
+ struct rk_nfc_nand_chip *rknand = rk_nfc_to_rknand(chip);
+ struct nand_ecc_ctrl *ecc = &chip->ecc;
+ int new_len, new_oob_len;
+ void *buf;
+ int ret;
+
+ if (chip->options & NAND_BUSWIDTH_16) {
+ dev_err(dev, "16 bits bus width not supported");
+ return -EINVAL;
+ }
+
+ if (ecc->engine_type != NAND_ECC_ENGINE_TYPE_ON_HOST)
+ return 0;
+
+ ret = rk_nfc_ecc_init(dev, mtd);
+ if (ret)
+ return ret;
+ rknand->spare_per_sector = ecc->bytes + NFC_SYS_DATA_SIZE;
+ rknand->metadata_size = NFC_SYS_DATA_SIZE * ecc->steps;
+
+ if (rknand->metadata_size < NFC_SYS_DATA_SIZE + 2) {
+ dev_err(dev,
+ "Driver needs at least %d bytes of meta data\n",
+ NFC_SYS_DATA_SIZE + 2);
+ return -EIO;
+ }
+
+ /* Check buffer first, avoid duplicate alloc buffer. */
+ new_len = mtd->writesize + mtd->oobsize;
+ if (nfc->buffer && new_len > nfc->buffer_size) {
+ buf = krealloc(nfc->buffer, new_len, GFP_KERNEL | GFP_DMA);
+ if (!buf)
+ return -ENOMEM;
+ nfc->buffer = buf;
+ nfc->buffer_size = new_len;
+ }
+
+ new_oob_len = ecc->steps * NFC_MAX_OOB_PER_STEP;
+ if (nfc->oob_buf && new_oob_len > nfc->oob_buf_size) {
+ buf = krealloc(nfc->oob_buf, new_oob_len,
+ GFP_KERNEL | GFP_DMA);
+ if (!buf) {
+ kfree(nfc->buffer);
+ nfc->buffer = NULL;
+ return -ENOMEM;
+ }
+ nfc->oob_buf = buf;
+ nfc->oob_buf_size = new_oob_len;
+ }
+
+ if (!nfc->buffer) {
+ nfc->buffer = kzalloc(new_len, GFP_KERNEL | GFP_DMA);
+ if (!nfc->buffer)
+ return -ENOMEM;
+ nfc->buffer_size = new_len;
+ }
+
+ if (!nfc->oob_buf) {
+ nfc->oob_buf = kzalloc(new_oob_len, GFP_KERNEL | GFP_DMA);
+ if (!nfc->oob_buf) {
+ kfree(nfc->buffer);
+ nfc->buffer = NULL;
+ return -ENOMEM;
+ }
+ nfc->oob_buf_size = new_oob_len;
+ }
+
+ nfc->page_buf = nfc->buffer;
+
+ chip->ecc.write_page_raw = rk_nfc_write_page_raw;
+ chip->ecc.write_page = rk_nfc_write_page_hwecc;
+ chip->ecc.write_oob_raw = rk_nfc_write_oob;
+ chip->ecc.write_oob = rk_nfc_write_oob;
+
+ chip->ecc.read_page_raw = rk_nfc_read_page_raw;
+ chip->ecc.read_page = rk_nfc_read_page_hwecc;
+ chip->ecc.read_oob_raw = rk_nfc_read_oob;
+ chip->ecc.read_oob = rk_nfc_read_oob;
+
+ return 0;
+}
+
+static const struct nand_controller_ops rk_nfc_controller_ops = {
+ .attach_chip = rk_nfc_attach_chip,
+ .exec_op = rk_nfc_exec_op,
+ .setup_interface = rk_nfc_setup_data_interface,
+};
+
+static int rk_nfc_nand_chip_init(struct device *dev, struct rk_nfc *nfc,
+ struct device_node *np)
+{
+ struct rk_nfc_nand_chip *rknand;
+ struct nand_chip *chip;
+ struct mtd_info *mtd;
+ int nsels;
+ u32 tmp;
+ int ret;
+ int i;
+
+ if (!of_get_property(np, "reg", &nsels))
+ return -ENODEV;
+ nsels /= sizeof(u32);
+ if (!nsels || nsels > NFC_MAX_NSELS) {
+ dev_err(dev, "invalid reg property size %d\n", nsels);
+ return -EINVAL;
+ }
+
+ rknand = devm_kzalloc(dev, sizeof(*rknand) + nsels * sizeof(u8),
+ GFP_KERNEL);
+ if (!rknand)
+ return -ENOMEM;
+
+ rknand->nsels = nsels;
+ for (i = 0; i < nsels; i++) {
+ ret = of_property_read_u32_index(np, "reg", i, &tmp);
+ if (ret) {
+ dev_err(dev, "reg property failure : %d\n", ret);
+ return ret;
+ }
+
+ if (tmp >= NFC_MAX_NSELS) {
+ dev_err(dev, "invalid CS: %u\n", tmp);
+ return -EINVAL;
+ }
+
+ if (test_and_set_bit(tmp, &nfc->assigned_cs)) {
+ dev_err(dev, "CS %u already assigned\n", tmp);
+ return -EINVAL;
+ }
+
+ rknand->sels[i] = tmp;
+ }
+
+ chip = &rknand->chip;
+ chip->controller = &nfc->controller;
+
+ nand_set_flash_node(chip, np);
+
+ nand_set_controller_data(chip, nfc);
+
+ chip->options |= NAND_USES_DMA | NAND_NO_SUBPAGE_WRITE;
+ chip->bbt_options = NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB;
+
+ /* Set default mode in case dt entry is missing. */
+ chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
+
+ mtd = nand_to_mtd(chip);
+ mtd->owner = THIS_MODULE;
+ mtd->dev.parent = dev;
+
+ if (!mtd->name) {
+ dev_err(nfc->dev, "NAND label property is mandatory\n");
+ return -EINVAL;
+ }
+
+ mtd_set_ooblayout(mtd, &rk_nfc_ooblayout_ops);
+ rk_nfc_hw_init(nfc);
+ ret = nand_scan(chip, nsels);
+ if (ret)
+ return ret;
+
+ if (chip->options & NAND_IS_BOOT_MEDIUM) {
+ ret = of_property_read_u32(np, "rockchip,boot-blks", &tmp);
+ rknand->boot_blks = ret ? 0 : tmp;
+
+ ret = of_property_read_u32(np, "rockchip,boot-ecc-strength",
+ &tmp);
+ rknand->boot_ecc = ret ? chip->ecc.strength : tmp;
+ }
+
+ ret = mtd_device_register(mtd, NULL, 0);
+ if (ret) {
+ dev_err(dev, "mtd parse partition error\n");
+ nand_cleanup(chip);
+ return ret;
+ }
+
+ list_add_tail(&rknand->node, &nfc->chips);
+
+ return 0;
+}
+
+static void rk_nfc_chips_cleanup(struct rk_nfc *nfc)
+{
+ struct rk_nfc_nand_chip *rknand, *tmp;
+ struct nand_chip *chip;
+ int ret;
+
+ list_for_each_entry_safe(rknand, tmp, &nfc->chips, node) {
+ chip = &rknand->chip;
+ ret = mtd_device_unregister(nand_to_mtd(chip));
+ WARN_ON(ret);
+ nand_cleanup(chip);
+ list_del(&rknand->node);
+ }
+}
+
+static int rk_nfc_nand_chips_init(struct device *dev, struct rk_nfc *nfc)
+{
+ struct device_node *np = dev->of_node, *nand_np;
+ int nchips = of_get_child_count(np);
+ int ret;
+
+ if (!nchips || nchips > NFC_MAX_NSELS) {
+ dev_err(nfc->dev, "Incorrect number of NAND chips (%d)\n",
+ nchips);
+ return -EINVAL;
+ }
+
+ for_each_child_of_node(np, nand_np) {
+ ret = rk_nfc_nand_chip_init(dev, nfc, nand_np);
+ if (ret) {
+ of_node_put(nand_np);
+ rk_nfc_chips_cleanup(nfc);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static struct nfc_cfg nfc_v6_cfg = {
+ .type = NFC_V6,
+ .ecc_strengths = {60, 40, 24, 16},
+ .ecc_cfgs = {
+ 0x00040011, 0x00040001, 0x00000011, 0x00000001,
+ },
+ .flctl_off = 0x08,
+ .bchctl_off = 0x0C,
+ .dma_cfg_off = 0x10,
+ .dma_data_buf_off = 0x14,
+ .dma_oob_buf_off = 0x18,
+ .dma_st_off = 0x1C,
+ .bch_st_off = 0x20,
+ .randmz_off = 0x150,
+ .int_en_off = 0x16C,
+ .int_clr_off = 0x170,
+ .int_st_off = 0x174,
+ .oob0_off = 0x200,
+ .oob1_off = 0x230,
+ .ecc0 = {
+ .err_flag_bit = 2,
+ .low = 3,
+ .low_mask = 0x1F,
+ .low_bn = 5,
+ .high = 27,
+ .high_mask = 0x1,
+ },
+ .ecc1 = {
+ .err_flag_bit = 15,
+ .low = 16,
+ .low_mask = 0x1F,
+ .low_bn = 5,
+ .high = 29,
+ .high_mask = 0x1,
+ },
+};
+
+static struct nfc_cfg nfc_v8_cfg = {
+ .type = NFC_V8,
+ .ecc_strengths = {16, 16, 16, 16},
+ .ecc_cfgs = {
+ 0x00000001, 0x00000001, 0x00000001, 0x00000001,
+ },
+ .flctl_off = 0x08,
+ .bchctl_off = 0x0C,
+ .dma_cfg_off = 0x10,
+ .dma_data_buf_off = 0x14,
+ .dma_oob_buf_off = 0x18,
+ .dma_st_off = 0x1C,
+ .bch_st_off = 0x20,
+ .randmz_off = 0x150,
+ .int_en_off = 0x16C,
+ .int_clr_off = 0x170,
+ .int_st_off = 0x174,
+ .oob0_off = 0x200,
+ .oob1_off = 0x230,
+ .ecc0 = {
+ .err_flag_bit = 2,
+ .low = 3,
+ .low_mask = 0x1F,
+ .low_bn = 5,
+ .high = 27,
+ .high_mask = 0x1,
+ },
+ .ecc1 = {
+ .err_flag_bit = 15,
+ .low = 16,
+ .low_mask = 0x1F,
+ .low_bn = 5,
+ .high = 29,
+ .high_mask = 0x1,
+ },
+};
+
+static struct nfc_cfg nfc_v9_cfg = {
+ .type = NFC_V9,
+ .ecc_strengths = {70, 60, 40, 16},
+ .ecc_cfgs = {
+ 0x00000001, 0x06000001, 0x04000001, 0x02000001,
+ },
+ .flctl_off = 0x10,
+ .bchctl_off = 0x20,
+ .dma_cfg_off = 0x30,
+ .dma_data_buf_off = 0x34,
+ .dma_oob_buf_off = 0x38,
+ .dma_st_off = 0x3C,
+ .bch_st_off = 0x150,
+ .randmz_off = 0x208,
+ .int_en_off = 0x120,
+ .int_clr_off = 0x124,
+ .int_st_off = 0x128,
+ .oob0_off = 0x200,
+ .oob1_off = 0x204,
+ .ecc0 = {
+ .err_flag_bit = 2,
+ .low = 3,
+ .low_mask = 0x7F,
+ .low_bn = 7,
+ .high = 0,
+ .high_mask = 0x0,
+ },
+ .ecc1 = {
+ .err_flag_bit = 18,
+ .low = 19,
+ .low_mask = 0x7F,
+ .low_bn = 7,
+ .high = 0,
+ .high_mask = 0x0,
+ },
+};
+
+static const struct of_device_id rk_nfc_id_table[] = {
+ {
+ .compatible = "rockchip,px30-nfc",
+ .data = &nfc_v9_cfg
+ },
+ {
+ .compatible = "rockchip,rk2928-nfc",
+ .data = &nfc_v6_cfg
+ },
+ {
+ .compatible = "rockchip,rv1108-nfc",
+ .data = &nfc_v8_cfg
+ },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, rk_nfc_id_table);
+
+static int rk_nfc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct rk_nfc *nfc;
+ int ret, irq;
+
+ nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL);
+ if (!nfc)
+ return -ENOMEM;
+
+ nand_controller_init(&nfc->controller);
+ INIT_LIST_HEAD(&nfc->chips);
+ nfc->controller.ops = &rk_nfc_controller_ops;
+
+ nfc->cfg = of_device_get_match_data(dev);
+ nfc->dev = dev;
+
+ init_completion(&nfc->done);
+
+ nfc->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(nfc->regs)) {
+ ret = PTR_ERR(nfc->regs);
+ goto release_nfc;
+ }
+
+ nfc->nfc_clk = devm_clk_get(dev, "nfc");
+ if (IS_ERR(nfc->nfc_clk)) {
+ dev_dbg(dev, "no nfc clk\n");
+ /* Some earlier models, such as rk3066, have no nfc clk. */
+ }
+
+ nfc->ahb_clk = devm_clk_get(dev, "ahb");
+ if (IS_ERR(nfc->ahb_clk)) {
+ dev_err(dev, "no ahb clk\n");
+ ret = PTR_ERR(nfc->ahb_clk);
+ goto release_nfc;
+ }
+
+ ret = rk_nfc_enable_clks(dev, nfc);
+ if (ret)
+ goto release_nfc;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(dev, "no nfc irq resource\n");
+ ret = -EINVAL;
+ goto clk_disable;
+ }
+
+ writel(0, nfc->regs + nfc->cfg->int_en_off);
+ ret = devm_request_irq(dev, irq, rk_nfc_irq, 0x0, "rk-nand", nfc);
+ if (ret) {
+ dev_err(dev, "failed to request nfc irq\n");
+ goto clk_disable;
+ }
+
+ platform_set_drvdata(pdev, nfc);
+
+ ret = rk_nfc_nand_chips_init(dev, nfc);
+ if (ret) {
+ dev_err(dev, "failed to init NAND chips\n");
+ goto clk_disable;
+ }
+ return 0;
+
+clk_disable:
+ rk_nfc_disable_clks(nfc);
+release_nfc:
+ return ret;
+}
+
+static int rk_nfc_remove(struct platform_device *pdev)
+{
+ struct rk_nfc *nfc = platform_get_drvdata(pdev);
+
+ kfree(nfc->buffer);
+ kfree(nfc->oob_buf);
+ rk_nfc_chips_cleanup(nfc);
+ rk_nfc_disable_clks(nfc);
+
+ return 0;
+}
+
+static int __maybe_unused rk_nfc_suspend(struct device *dev)
+{
+ struct rk_nfc *nfc = dev_get_drvdata(dev);
+
+ rk_nfc_disable_clks(nfc);
+
+ return 0;
+}
+
+static int __maybe_unused rk_nfc_resume(struct device *dev)
+{
+ struct rk_nfc *nfc = dev_get_drvdata(dev);
+ struct rk_nfc_nand_chip *rknand;
+ struct nand_chip *chip;
+ int ret;
+ u32 i;
+
+ ret = rk_nfc_enable_clks(dev, nfc);
+ if (ret)
+ return ret;
+
+ /* Reset NAND chip if VCC was powered off. */
+ list_for_each_entry(rknand, &nfc->chips, node) {
+ chip = &rknand->chip;
+ for (i = 0; i < rknand->nsels; i++)
+ nand_reset(chip, i);
+ }
+
+ return 0;
+}
+
+static const struct dev_pm_ops rk_nfc_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(rk_nfc_suspend, rk_nfc_resume)
+};
+
+static struct platform_driver rk_nfc_driver = {
+ .probe = rk_nfc_probe,
+ .remove = rk_nfc_remove,
+ .driver = {
+ .name = "rockchip-nfc",
+ .of_match_table = rk_nfc_id_table,
+ .pm = &rk_nfc_pm_ops,
+ },
+};
+
+module_platform_driver(rk_nfc_driver);
+
+MODULE_LICENSE("Dual MIT/GPL");
+MODULE_AUTHOR("Yifeng Zhao <yifeng.zhao@rock-chips.com>");
+MODULE_DESCRIPTION("Rockchip Nand Flash Controller Driver");
+MODULE_ALIAS("platform:rockchip-nand-controller");
From b02351f0d62ff722f4f9ab87ad39607bc1993640 Mon Sep 17 00:00:00 2001
From: Yifeng Zhao <yifeng.zhao@rock-chips.com>
Date: Wed, 28 Oct 2020 17:53:25 +0800
Subject: [PATCH] MAINTAINERS: add maintainers to ROCKCHIP NFC
Add maintainers to ROCKCHIP NFC.
Signed-off-by: Yifeng Zhao <yifeng.zhao@rock-chips.com>
---
MAINTAINERS | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/MAINTAINERS b/MAINTAINERS
index 867157311dc8..0a14444b5f65 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2387,12 +2387,12 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
L: linux-rockchip@lists.infradead.org
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git
+F: Documentation/devicetree/bindings/*/*rockchip*.yaml
F: Documentation/devicetree/bindings/i2c/i2c-rk3x.yaml
-F: Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.yaml
-F: Documentation/devicetree/bindings/spi/spi-rockchip.yaml
F: arch/arm/boot/dts/rk3*
F: arch/arm/boot/dts/rv1108*
F: arch/arm/mach-rockchip/
+F: drivers/*/*/*/*rockchip*
F: drivers/*/*/*rockchip*
F: drivers/*/*rockchip*
F: drivers/clk/rockchip/
From 821a95a89d8384743e96c984f37fb364bfe8b011 Mon Sep 17 00:00:00 2001
From: Yifeng Zhao <zyf@rock-chips.com>
Date: Wed, 28 Oct 2020 17:53:26 +0800
Subject: [PATCH] arm64: dts: rockchip: Add NFC node for RK3308 SoC
Add NAND FLASH Controller(NFC) node for RK3308 SoC.
Signed-off-by: Yifeng Zhao <zyf@rock-chips.com>
Signed-off-by: Yifeng Zhao <yifeng.zhao@rock-chips.com>
---
arch/arm64/boot/dts/rockchip/rk3308.dtsi | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/arch/arm64/boot/dts/rockchip/rk3308.dtsi b/arch/arm64/boot/dts/rockchip/rk3308.dtsi
index 2560b98771ca..7211fab7a6e4 100644
--- a/arch/arm64/boot/dts/rockchip/rk3308.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3308.dtsi
@@ -629,6 +629,21 @@ sdio: mmc@ff4a0000 {
status = "disabled";
};
+ nfc: nand-controller@ff4b0000 {
+ compatible = "rockchip,rk3308-nfc",
+ "rockchip,rv1108-nfc";
+ reg = <0x0 0xff4b0000 0x0 0x4000>;
+ interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cru HCLK_NANDC>, <&cru SCLK_NANDC>;
+ clock-names = "ahb", "nfc";
+ assigned-clocks = <&cru SCLK_NANDC>;
+ assigned-clock-rates = <150000000>;
+ pinctrl-0 = <&flash_ale &flash_bus8 &flash_cle &flash_csn0
+ &flash_rdn &flash_rdy &flash_wrn>;
+ pinctrl-names = "default";
+ status = "disabled";
+ };
+
cru: clock-controller@ff500000 {
compatible = "rockchip,rk3308-cru";
reg = <0x0 0xff500000 0x0 0x1000>;
From 75679412eebab96c9a9dc190a8e5b2a9f5d0d8d7 Mon Sep 17 00:00:00 2001
From: Yifeng Zhao <yifeng.zhao@rock-chips.com>
Date: Wed, 28 Oct 2020 17:54:14 +0800
Subject: [PATCH] arm64: dts: rockchip: Add NFC node for PX30 SoC
Add NAND FLASH Controller(NFC) node for PX30 SoC.
Signed-off-by: Yifeng Zhao <yifeng.zhao@rock-chips.com>
---
arch/arm64/boot/dts/rockchip/px30.dtsi | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/arch/arm64/boot/dts/rockchip/px30.dtsi b/arch/arm64/boot/dts/rockchip/px30.dtsi
index 2695ea8cda14..6cd67e80d623 100644
--- a/arch/arm64/boot/dts/rockchip/px30.dtsi
+++ b/arch/arm64/boot/dts/rockchip/px30.dtsi
@@ -973,6 +973,21 @@ emmc: mmc@ff390000 {
status = "disabled";
};
+ nfc: nand-controller@ff3b0000 {
+ compatible = "rockchip,px30-nfc";
+ reg = <0x0 0xff3b0000 0x0 0x4000>;
+ interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cru HCLK_NANDC>, <&cru SCLK_NANDC>;
+ clock-names = "ahb", "nfc";
+ assigned-clocks = <&cru SCLK_NANDC>;
+ assigned-clock-rates = <150000000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&flash_ale &flash_bus8 &flash_cle &flash_cs0
+ &flash_rdn &flash_rdy &flash_wrn &flash_dqs>;
+ power-domains = <&power PX30_PD_MMC_NAND>;
+ status = "disabled";
+ };
+
gpu: gpu@ff400000 {
compatible = "rockchip,px30-mali", "arm,mali-bifrost";
reg = <0x0 0xff400000 0x0 0x4000>;
From 4427805765fdfe5840894eac2b440e7c6e5f0e8b Mon Sep 17 00:00:00 2001
From: Yifeng Zhao <yifeng.zhao@rock-chips.com>
Date: Wed, 28 Oct 2020 17:54:15 +0800
Subject: [PATCH] arm: dts: rockchip: Add NFC node for RV1108 SoC
Add NAND FLASH Controller(NFC) node for RV1108 SoC.
Signed-off-by: Yifeng Zhao <yifeng.zhao@rock-chips.com>
---
arch/arm/boot/dts/rv1108.dtsi | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/arch/arm/boot/dts/rv1108.dtsi b/arch/arm/boot/dts/rv1108.dtsi
index a1a08cb9364e..1696ea19488b 100644
--- a/arch/arm/boot/dts/rv1108.dtsi
+++ b/arch/arm/boot/dts/rv1108.dtsi
@@ -452,6 +452,17 @@ cru: clock-controller@20200000 {
#reset-cells = <1>;
};
+ nfc: nand-controller@30100000 {
+ compatible = "rockchip,rv1108-nfc";
+ reg = <0x30100000 0x1000>;
+ interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cru HCLK_NANDC>, <&cru SCLK_NANDC>;
+ clock-names = "ahb", "nfc";
+ assigned-clocks = <&cru SCLK_NANDC>;
+ assigned-clock-rates = <150000000>;
+ status = "disabled";
+ };
+
emmc: mmc@30110000 {
compatible = "rockchip,rv1108-dw-mshc", "rockchip,rk3288-dw-mshc";
reg = <0x30110000 0x4000>;
From f0424cb442feb3431de15631b3a757bdf828db95 Mon Sep 17 00:00:00 2001
From: Yifeng Zhao <yifeng.zhao@rock-chips.com>
Date: Wed, 28 Oct 2020 17:54:16 +0800
Subject: [PATCH] arm: dts: rockchip: Add NFC node for RK2928 and other SoCs
Add NAND FLASH Controller(NFC) node for RK2928, RK3066, RK3168
and RK3188 SoCs.
Signed-off-by: Yifeng Zhao <yifeng.zhao@rock-chips.com>
---
arch/arm/boot/dts/rk3xxx.dtsi | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/arch/arm/boot/dts/rk3xxx.dtsi b/arch/arm/boot/dts/rk3xxx.dtsi
index 859a7477909f..97415180d5bb 100644
--- a/arch/arm/boot/dts/rk3xxx.dtsi
+++ b/arch/arm/boot/dts/rk3xxx.dtsi
@@ -276,6 +276,15 @@ emmc: mmc@1021c000 {
status = "disabled";
};
+ nfc: nand-controller@10500000 {
+ compatible = "rockchip,rk2928-nfc";
+ reg = <0x10500000 0x4000>;
+ interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cru HCLK_NANDC0>;
+ clock-names = "ahb";
+ status = "disabled";
+ };
+
pmu: pmu@20004000 {
compatible = "rockchip,rk3066-pmu", "syscon", "simple-mfd";
reg = <0x20004000 0x100>;
From 39e1fd8036bac7c31ee7409b9f248d6f76e9cf87 Mon Sep 17 00:00:00 2001
From: Yifeng Zhao <yifeng.zhao@rock-chips.com>
Date: Wed, 28 Oct 2020 17:54:17 +0800
Subject: [PATCH] arm: dts: rockchip: Add NFC node for RK3036 SoC
Add NAND FLASH Controller(NFC) node for RK3036 SoC.
Signed-off-by: Yifeng Zhao <yifeng.zhao@rock-chips.com>
---
arch/arm/boot/dts/rk3036.dtsi | 52 +++++++++++++++++++++++++++++++++++
1 file changed, 52 insertions(+)
diff --git a/arch/arm/boot/dts/rk3036.dtsi b/arch/arm/boot/dts/rk3036.dtsi
index 093567022386..dda5a1f79aca 100644
--- a/arch/arm/boot/dts/rk3036.dtsi
+++ b/arch/arm/boot/dts/rk3036.dtsi
@@ -292,6 +292,21 @@ i2s: i2s@10220000 {
status = "disabled";
};
+ nfc: nand-controller@10500000 {
+ compatible = "rockchip,rk3036-nfc",
+ "rockchip,rk2928-nfc";
+ reg = <0x10500000 0x4000>;
+ interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cru HCLK_NANDC>, <&cru SCLK_NANDC>;
+ clock-names = "ahb", "nfc";
+ assigned-clocks = <&cru SCLK_NANDC>;
+ assigned-clock-rates = <150000000>;
+ pinctrl-0 = <&flash_ale &flash_bus8 &flash_cle &flash_csn0
+ &flash_rdn &flash_rdy &flash_wrn>;
+ pinctrl-names = "default";
+ status = "disabled";
+ };
+
cru: clock-controller@20000000 {
compatible = "rockchip,rk3036-cru";
reg = <0x20000000 0x1000>;
@@ -643,6 +658,43 @@ emmc_bus8: emmc-bus8 {
};
};
+ nfc {
+ flash_ale: flash-ale {
+ rockchip,pins = <2 RK_PA0 1 &pcfg_pull_default>;
+ };
+
+ flash_bus8: flash-bus8 {
+ rockchip,pins = <1 RK_PD0 1 &pcfg_pull_default>,
+ <1 RK_PD1 1 &pcfg_pull_default>,
+ <1 RK_PD2 1 &pcfg_pull_default>,
+ <1 RK_PD3 1 &pcfg_pull_default>,
+ <1 RK_PD4 1 &pcfg_pull_default>,
+ <1 RK_PD5 1 &pcfg_pull_default>,
+ <1 RK_PD6 1 &pcfg_pull_default>,
+ <1 RK_PD7 1 &pcfg_pull_default>;
+ };
+
+ flash_cle: flash-cle {
+ rockchip,pins = <2 RK_PA1 1 &pcfg_pull_default>;
+ };
+
+ flash_csn0: flash-csn0 {
+ rockchip,pins = <2 RK_PA6 1 &pcfg_pull_default>;
+ };
+
+ flash_rdn: flash-rdn {
+ rockchip,pins = <2 RK_PA3 1 &pcfg_pull_default>;
+ };
+
+ flash_rdy: flash-rdy {
+ rockchip,pins = <2 RK_PA4 1 &pcfg_pull_default>;
+ };
+
+ flash_wrn: flash-wrn {
+ rockchip,pins = <2 RK_PA2 1 &pcfg_pull_default>;
+ };
+ };
+
emac {
emac_xfer: emac-xfer {
rockchip,pins = <2 RK_PB2 1 &pcfg_pull_default>, /* crs_dvalid */
From ab3efcbbee3a7009cc6321d9f74f4123d308673b Mon Sep 17 00:00:00 2001
From: Elaine Zhang <zhangqing@rock-chips.com>
Date: Wed, 14 Oct 2020 10:28:08 +0800
Subject: [PATCH] clk: rockchip: Add supprot to limit input rate for fractional
divider
From Rockchips fractional divider usage, some clocks can be generated
by fractional divider, but the input clock frequency of fractional
divider should be less than a specified value.
.i.e:
|--\
---[GPLL]---| \ |--\
---[CPLL]---|mux|--[GATE]--[DIV]-----------------------| \
---[NPLL]---| / | |mux|--[GATE]--
|--/ |--[GATE]--[FRACDIV]--| /
|--/
The FRACDIV frequency is designed to be only 300M(Different SOC
implementations are different).But the GPLL or CPLL may be 1200M.
Must be added to limit to ensure that the design is not exceeded.
Signed-off-by: Finley Xiao <finley.xiao@rock-chips.com>
Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
---
drivers/clk/rockchip/clk-px30.c | 29 +++++++++----------
drivers/clk/rockchip/clk-rk3036.c | 13 +++++----
drivers/clk/rockchip/clk-rk3128.c | 15 ++++++----
drivers/clk/rockchip/clk-rk3188.c | 24 +++++++++-------
drivers/clk/rockchip/clk-rk3228.c | 18 +++++++-----
drivers/clk/rockchip/clk-rk3288.c | 19 +++++++------
drivers/clk/rockchip/clk-rk3308.c | 46 +++++++++++++++++--------------
drivers/clk/rockchip/clk-rk3328.c | 17 +++++++-----
drivers/clk/rockchip/clk-rk3368.c | 17 +++++++-----
drivers/clk/rockchip/clk-rk3399.c | 32 ++++++++++++---------
drivers/clk/rockchip/clk-rv1108.c | 14 ++++++----
drivers/clk/rockchip/clk.c | 21 ++++++++++++--
drivers/clk/rockchip/clk.h | 10 +++++--
include/linux/clk-provider.h | 2 ++
14 files changed, 168 insertions(+), 109 deletions(-)
diff --git a/drivers/clk/rockchip/clk-px30.c b/drivers/clk/rockchip/clk-px30.c
index 6fb9c98b7d24..f075eb922bab 100644
--- a/drivers/clk/rockchip/clk-px30.c
+++ b/drivers/clk/rockchip/clk-px30.c
@@ -13,6 +13,7 @@
#include "clk.h"
#define PX30_GRF_SOC_STATUS0 0x480
+#define PX30_FRAC_MAX_PRATE 600000000
enum px30_plls {
apll, dpll, cpll, npll, apll_b_h, apll_b_l,
@@ -424,7 +425,7 @@ static struct rockchip_clk_branch px30_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "dclk_vopb_frac", "dclk_vopb_src", CLK_SET_RATE_PARENT,
PX30_CLKSEL_CON(6), 0,
PX30_CLKGATE_CON(2), 3, GFLAGS,
- &px30_dclk_vopb_fracmux),
+ &px30_dclk_vopb_fracmux, 0),
GATE(DCLK_VOPB, "dclk_vopb", "dclk_vopb_mux", CLK_SET_RATE_PARENT,
PX30_CLKGATE_CON(2), 4, GFLAGS),
COMPOSITE(0, "dclk_vopl_src", mux_npll_cpll_p, 0,
@@ -433,7 +434,7 @@ static struct rockchip_clk_branch px30_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "dclk_vopl_frac", "dclk_vopl_src", CLK_SET_RATE_PARENT,
PX30_CLKSEL_CON(9), 0,
PX30_CLKGATE_CON(2), 7, GFLAGS,
- &px30_dclk_vopl_fracmux),
+ &px30_dclk_vopl_fracmux, 0),
GATE(DCLK_VOPL, "dclk_vopl", "dclk_vopl_mux", CLK_SET_RATE_PARENT,
PX30_CLKGATE_CON(2), 8, GFLAGS),
@@ -591,7 +592,7 @@ static struct rockchip_clk_branch px30_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "clk_pdm_frac", "clk_pdm_src", CLK_SET_RATE_PARENT,
PX30_CLKSEL_CON(27), 0,
PX30_CLKGATE_CON(9), 10, GFLAGS,
- &px30_pdm_fracmux),
+ &px30_pdm_fracmux, PX30_FRAC_MAX_PRATE),
GATE(SCLK_PDM, "clk_pdm", "clk_pdm_mux", CLK_SET_RATE_PARENT,
PX30_CLKGATE_CON(9), 11, GFLAGS),
@@ -601,7 +602,7 @@ static struct rockchip_clk_branch px30_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "clk_i2s0_tx_frac", "clk_i2s0_tx_src", CLK_SET_RATE_PARENT,
PX30_CLKSEL_CON(29), 0,
PX30_CLKGATE_CON(9), 13, GFLAGS,
- &px30_i2s0_tx_fracmux),
+ &px30_i2s0_tx_fracmux, PX30_FRAC_MAX_PRATE),
COMPOSITE_NODIV(SCLK_I2S0_TX, "clk_i2s0_tx", mux_i2s0_tx_rx_p, CLK_SET_RATE_PARENT,
PX30_CLKSEL_CON(28), 12, 1, MFLAGS,
PX30_CLKGATE_CON(9), 14, GFLAGS),
@@ -617,7 +618,7 @@ static struct rockchip_clk_branch px30_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "clk_i2s0_rx_frac", "clk_i2s0_rx_src", CLK_SET_RATE_PARENT,
PX30_CLKSEL_CON(59), 0,
PX30_CLKGATE_CON(17), 1, GFLAGS,
- &px30_i2s0_rx_fracmux),
+ &px30_i2s0_rx_fracmux, PX30_FRAC_MAX_PRATE),
COMPOSITE_NODIV(SCLK_I2S0_RX, "clk_i2s0_rx", mux_i2s0_rx_tx_p, CLK_SET_RATE_PARENT,
PX30_CLKSEL_CON(58), 12, 1, MFLAGS,
PX30_CLKGATE_CON(17), 2, GFLAGS),
@@ -633,7 +634,7 @@ static struct rockchip_clk_branch px30_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "clk_i2s1_frac", "clk_i2s1_src", CLK_SET_RATE_PARENT,
PX30_CLKSEL_CON(31), 0,
PX30_CLKGATE_CON(10), 1, GFLAGS,
- &px30_i2s1_fracmux),
+ &px30_i2s1_fracmux, PX30_FRAC_MAX_PRATE),
GATE(SCLK_I2S1, "clk_i2s1", "clk_i2s1_mux", CLK_SET_RATE_PARENT,
PX30_CLKGATE_CON(10), 2, GFLAGS),
COMPOSITE_NODIV(0, "clk_i2s1_out_pre", mux_i2s1_out_p, 0,
@@ -648,7 +649,7 @@ static struct rockchip_clk_branch px30_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "clk_i2s2_frac", "clk_i2s2_src", CLK_SET_RATE_PARENT,
PX30_CLKSEL_CON(33), 0,
PX30_CLKGATE_CON(10), 5, GFLAGS,
- &px30_i2s2_fracmux),
+ &px30_i2s2_fracmux, PX30_FRAC_MAX_PRATE),
GATE(SCLK_I2S2, "clk_i2s2", "clk_i2s2_mux", CLK_SET_RATE_PARENT,
PX30_CLKGATE_CON(10), 6, GFLAGS),
COMPOSITE_NODIV(0, "clk_i2s2_out_pre", mux_i2s2_out_p, 0,
@@ -666,7 +667,7 @@ static struct rockchip_clk_branch px30_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "clk_uart1_frac", "clk_uart1_src", CLK_SET_RATE_PARENT,
PX30_CLKSEL_CON(36), 0,
PX30_CLKGATE_CON(10), 14, GFLAGS,
- &px30_uart1_fracmux),
+ &px30_uart1_fracmux, PX30_FRAC_MAX_PRATE),
GATE(SCLK_UART1, "clk_uart1", "clk_uart1_mux", CLK_SET_RATE_PARENT,
PX30_CLKGATE_CON(10), 15, GFLAGS),
@@ -679,7 +680,7 @@ static struct rockchip_clk_branch px30_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "clk_uart2_frac", "clk_uart2_src", CLK_SET_RATE_PARENT,
PX30_CLKSEL_CON(39), 0,
PX30_CLKGATE_CON(11), 2, GFLAGS,
- &px30_uart2_fracmux),
+ &px30_uart2_fracmux, PX30_FRAC_MAX_PRATE),
GATE(SCLK_UART2, "clk_uart2", "clk_uart2_mux", CLK_SET_RATE_PARENT,
PX30_CLKGATE_CON(11), 3, GFLAGS),
@@ -692,7 +693,7 @@ static struct rockchip_clk_branch px30_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "clk_uart3_frac", "clk_uart3_src", CLK_SET_RATE_PARENT,
PX30_CLKSEL_CON(42), 0,
PX30_CLKGATE_CON(11), 6, GFLAGS,
- &px30_uart3_fracmux),
+ &px30_uart3_fracmux, PX30_FRAC_MAX_PRATE),
GATE(SCLK_UART3, "clk_uart3", "clk_uart3_mux", CLK_SET_RATE_PARENT,
PX30_CLKGATE_CON(11), 7, GFLAGS),
@@ -705,7 +706,7 @@ static struct rockchip_clk_branch px30_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "clk_uart4_frac", "clk_uart4_src", CLK_SET_RATE_PARENT,
PX30_CLKSEL_CON(45), 0,
PX30_CLKGATE_CON(11), 10, GFLAGS,
- &px30_uart4_fracmux),
+ &px30_uart4_fracmux, PX30_FRAC_MAX_PRATE),
GATE(SCLK_UART4, "clk_uart4", "clk_uart4_mux", CLK_SET_RATE_PARENT,
PX30_CLKGATE_CON(11), 11, GFLAGS),
@@ -718,7 +719,7 @@ static struct rockchip_clk_branch px30_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "clk_uart5_frac", "clk_uart5_src", CLK_SET_RATE_PARENT,
PX30_CLKSEL_CON(48), 0,
PX30_CLKGATE_CON(11), 14, GFLAGS,
- &px30_uart5_fracmux),
+ &px30_uart5_fracmux, PX30_FRAC_MAX_PRATE),
GATE(SCLK_UART5, "clk_uart5", "clk_uart5_mux", CLK_SET_RATE_PARENT,
PX30_CLKGATE_CON(11), 15, GFLAGS),
@@ -918,7 +919,7 @@ static struct rockchip_clk_branch px30_clk_pmu_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "clk_rtc32k_frac", "xin24m", CLK_IGNORE_UNUSED,
PX30_PMU_CLKSEL_CON(1), 0,
PX30_PMU_CLKGATE_CON(0), 13, GFLAGS,
- &px30_rtc32k_pmu_fracmux),
+ &px30_rtc32k_pmu_fracmux, 0),
COMPOSITE_NOMUX(XIN24M_DIV, "xin24m_div", "xin24m", CLK_IGNORE_UNUSED,
PX30_PMU_CLKSEL_CON(0), 8, 5, DFLAGS,
@@ -940,7 +941,7 @@ static struct rockchip_clk_branch px30_clk_pmu_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "clk_uart0_frac", "clk_uart0_pmu_src", CLK_SET_RATE_PARENT,
PX30_PMU_CLKSEL_CON(5), 0,
PX30_PMU_CLKGATE_CON(1), 2, GFLAGS,
- &px30_uart0_pmu_fracmux),
+ &px30_uart0_pmu_fracmux, PX30_FRAC_MAX_PRATE),
GATE(SCLK_UART0_PMU, "clk_uart0_pmu", "clk_uart0_pmu_mux", CLK_SET_RATE_PARENT,
PX30_PMU_CLKGATE_CON(1), 3, GFLAGS),
diff --git a/drivers/clk/rockchip/clk-rk3036.c b/drivers/clk/rockchip/clk-rk3036.c
index 6a46f85ad837..80876c8f8c9d 100644
--- a/drivers/clk/rockchip/clk-rk3036.c
+++ b/drivers/clk/rockchip/clk-rk3036.c
@@ -16,6 +16,9 @@
#include "clk.h"
#define RK3036_GRF_SOC_STATUS0 0x14c
+#define RK3036_UART_FRAC_MAX_PRATE 600000000
+#define RK3036_I2S_FRAC_MAX_PRATE 600000000
+#define RK3036_SPDIF_FRAC_MAX_PRATE 600000000
enum rk3036_plls {
apll, dpll, gpll,
@@ -248,15 +251,15 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "uart0_frac", "uart0_src", CLK_SET_RATE_PARENT,
RK2928_CLKSEL_CON(17), 0,
RK2928_CLKGATE_CON(1), 9, GFLAGS,
- &rk3036_uart0_fracmux),
+ &rk3036_uart0_fracmux, RK3036_UART_FRAC_MAX_PRATE),
COMPOSITE_FRACMUX(0, "uart1_frac", "uart1_src", CLK_SET_RATE_PARENT,
RK2928_CLKSEL_CON(18), 0,
RK2928_CLKGATE_CON(1), 11, GFLAGS,
- &rk3036_uart1_fracmux),
+ &rk3036_uart1_fracmux, RK3036_UART_FRAC_MAX_PRATE),
COMPOSITE_FRACMUX(0, "uart2_frac", "uart2_src", CLK_SET_RATE_PARENT,
RK2928_CLKSEL_CON(19), 0,
RK2928_CLKGATE_CON(1), 13, GFLAGS,
- &rk3036_uart2_fracmux),
+ &rk3036_uart2_fracmux, RK3036_UART_FRAC_MAX_PRATE),
COMPOSITE(0, "aclk_vcodec", mux_pll_src_3plls_p, 0,
RK2928_CLKSEL_CON(32), 14, 2, MFLAGS, 8, 5, DFLAGS,
@@ -309,7 +312,7 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "i2s_frac", "i2s_src", CLK_SET_RATE_PARENT,
RK2928_CLKSEL_CON(7), 0,
RK2928_CLKGATE_CON(0), 10, GFLAGS,
- &rk3036_i2s_fracmux),
+ &rk3036_i2s_fracmux, RK3036_I2S_FRAC_MAX_PRATE),
COMPOSITE_NODIV(SCLK_I2S_OUT, "i2s_clkout", mux_i2s_clkout_p, 0,
RK2928_CLKSEL_CON(3), 12, 1, MFLAGS,
RK2928_CLKGATE_CON(0), 13, GFLAGS),
@@ -322,7 +325,7 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "spdif_frac", "spdif_src", 0,
RK2928_CLKSEL_CON(9), 0,
RK2928_CLKGATE_CON(2), 12, GFLAGS,
- &rk3036_spdif_fracmux),
+ &rk3036_spdif_fracmux, RK3036_SPDIF_FRAC_MAX_PRATE),
GATE(SCLK_OTGPHY0, "sclk_otgphy0", "xin12m", CLK_IGNORE_UNUSED,
RK2928_CLKGATE_CON(1), 5, GFLAGS),
diff --git a/drivers/clk/rockchip/clk-rk3128.c b/drivers/clk/rockchip/clk-rk3128.c
index 4b1122e98e16..9eecd56d06db 100644
--- a/drivers/clk/rockchip/clk-rk3128.c
+++ b/drivers/clk/rockchip/clk-rk3128.c
@@ -13,6 +13,9 @@
#include "clk.h"
#define RK3128_GRF_SOC_STATUS0 0x14c
+#define RK3128_UART_FRAC_MAX_PRATE 600000000
+#define RK3128_I2S_FRAC_MAX_PRATE 600000000
+#define RK3128_SPDIF_FRAC_MAX_PRATE 600000000
enum rk3128_plls {
apll, dpll, cpll, gpll,
@@ -359,7 +362,7 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "i2s0_frac", "i2s0_src", CLK_SET_RATE_PARENT,
RK2928_CLKSEL_CON(8), 0,
RK2928_CLKGATE_CON(4), 5, GFLAGS,
- &rk3128_i2s0_fracmux),
+ &rk3128_i2s0_fracmux, RK3128_I2S_FRAC_MAX_PRATE),
GATE(SCLK_I2S0, "sclk_i2s0", "i2s0_pre", CLK_SET_RATE_PARENT,
RK2928_CLKGATE_CON(4), 6, GFLAGS),
@@ -369,7 +372,7 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "i2s1_frac", "i2s1_src", CLK_SET_RATE_PARENT,
RK2928_CLKSEL_CON(7), 0,
RK2928_CLKGATE_CON(0), 10, GFLAGS,
- &rk3128_i2s1_fracmux),
+ &rk3128_i2s1_fracmux, RK3128_I2S_FRAC_MAX_PRATE),
GATE(SCLK_I2S1, "sclk_i2s1", "i2s1_pre", CLK_SET_RATE_PARENT,
RK2928_CLKGATE_CON(0), 14, GFLAGS),
COMPOSITE_NODIV(SCLK_I2S_OUT, "i2s_out", mux_i2s_out_p, 0,
@@ -382,7 +385,7 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "spdif_frac", "sclk_spdif_src", CLK_SET_RATE_PARENT,
RK2928_CLKSEL_CON(20), 0,
RK2928_CLKGATE_CON(2), 12, GFLAGS,
- &rk3128_spdif_fracmux),
+ &rk3128_spdif_fracmux, RK3128_SPDIF_FRAC_MAX_PRATE),
GATE(0, "jtag", "ext_jtag", CLK_IGNORE_UNUSED,
RK2928_CLKGATE_CON(1), 3, GFLAGS),
@@ -419,15 +422,15 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "uart0_frac", "uart0_src", CLK_SET_RATE_PARENT,
RK2928_CLKSEL_CON(17), 0,
RK2928_CLKGATE_CON(1), 9, GFLAGS,
- &rk3128_uart0_fracmux),
+ &rk3128_uart0_fracmux, RK3128_UART_FRAC_MAX_PRATE),
COMPOSITE_FRACMUX(0, "uart1_frac", "uart1_src", CLK_SET_RATE_PARENT,
RK2928_CLKSEL_CON(18), 0,
RK2928_CLKGATE_CON(1), 11, GFLAGS,
- &rk3128_uart1_fracmux),
+ &rk3128_uart1_fracmux, RK3128_UART_FRAC_MAX_PRATE),
COMPOSITE_FRACMUX(0, "uart2_frac", "uart2_src", CLK_SET_RATE_PARENT,
RK2928_CLKSEL_CON(19), 0,
RK2928_CLKGATE_CON(1), 13, GFLAGS,
- &rk3128_uart2_fracmux),
+ &rk3128_uart2_fracmux, RK3128_UART_FRAC_MAX_PRATE),
COMPOSITE(SCLK_MAC_SRC, "sclk_gmac_src", mux_pll_src_3plls_p, 0,
RK2928_CLKSEL_CON(5), 6, 2, MFLAGS, 0, 5, DFLAGS,
diff --git a/drivers/clk/rockchip/clk-rk3188.c b/drivers/clk/rockchip/clk-rk3188.c
index 730020fcc7fe..3970b68e9d9c 100644
--- a/drivers/clk/rockchip/clk-rk3188.c
+++ b/drivers/clk/rockchip/clk-rk3188.c
@@ -14,6 +14,10 @@
#define RK3066_GRF_SOC_STATUS 0x15c
#define RK3188_GRF_SOC_STATUS 0xac
+#define RK3188_UART_FRAC_MAX_PRATE 600000000
+#define RK3188_I2S_FRAC_MAX_PRATE 600000000
+#define RK3188_SPDIF_FRAC_MAX_PRATE 600000000
+#define RK3188_HSADC_FRAC_MAX_PRATE 300000000
enum rk3188_plls {
apll, cpll, dpll, gpll,
@@ -363,7 +367,7 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "hsadc_frac", "hsadc_src", 0,
RK2928_CLKSEL_CON(23), 0,
RK2928_CLKGATE_CON(2), 7, GFLAGS,
- &common_hsadc_out_fracmux),
+ &common_hsadc_out_fracmux, RK3188_HSADC_FRAC_MAX_PRATE),
INVERTER(SCLK_HSADC, "sclk_hsadc", "sclk_hsadc_out",
RK2928_CLKSEL_CON(22), 7, IFLAGS),
@@ -377,7 +381,7 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "spdif_frac", "spdif_pre", CLK_SET_RATE_PARENT,
RK2928_CLKSEL_CON(9), 0,
RK2928_CLKGATE_CON(0), 14, GFLAGS,
- &common_spdif_fracmux),
+ &common_spdif_fracmux, RK3188_SPDIF_FRAC_MAX_PRATE),
/*
* Clock-Architecture Diagram 4
@@ -411,28 +415,28 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "uart0_frac", "uart0_pre", 0,
RK2928_CLKSEL_CON(17), 0,
RK2928_CLKGATE_CON(1), 9, GFLAGS,
- &common_uart0_fracmux),
+ &common_uart0_fracmux, RK3188_UART_FRAC_MAX_PRATE),
COMPOSITE_NOMUX(0, "uart1_pre", "uart_src", 0,
RK2928_CLKSEL_CON(14), 0, 7, DFLAGS,
RK2928_CLKGATE_CON(1), 10, GFLAGS),
COMPOSITE_FRACMUX(0, "uart1_frac", "uart1_pre", 0,
RK2928_CLKSEL_CON(18), 0,
RK2928_CLKGATE_CON(1), 11, GFLAGS,
- &common_uart1_fracmux),
+ &common_uart1_fracmux, RK3188_UART_FRAC_MAX_PRATE),
COMPOSITE_NOMUX(0, "uart2_pre", "uart_src", 0,
RK2928_CLKSEL_CON(15), 0, 7, DFLAGS,
RK2928_CLKGATE_CON(1), 12, GFLAGS),
COMPOSITE_FRACMUX(0, "uart2_frac", "uart2_pre", 0,
RK2928_CLKSEL_CON(19), 0,
RK2928_CLKGATE_CON(1), 13, GFLAGS,
- &common_uart2_fracmux),
+ &common_uart2_fracmux, RK3188_UART_FRAC_MAX_PRATE),
COMPOSITE_NOMUX(0, "uart3_pre", "uart_src", 0,
RK2928_CLKSEL_CON(16), 0, 7, DFLAGS,
RK2928_CLKGATE_CON(1), 14, GFLAGS),
COMPOSITE_FRACMUX(0, "uart3_frac", "uart3_pre", 0,
RK2928_CLKSEL_CON(20), 0,
RK2928_CLKGATE_CON(1), 15, GFLAGS,
- &common_uart3_fracmux),
+ &common_uart3_fracmux, RK3188_UART_FRAC_MAX_PRATE),
GATE(SCLK_JTAG, "jtag", "ext_jtag", 0, RK2928_CLKGATE_CON(1), 3, GFLAGS),
@@ -618,21 +622,21 @@ static struct rockchip_clk_branch rk3066a_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "i2s0_frac", "i2s0_pre", 0,
RK2928_CLKSEL_CON(6), 0,
RK2928_CLKGATE_CON(0), 8, GFLAGS,
- &rk3066a_i2s0_fracmux),
+ &rk3066a_i2s0_fracmux, RK3188_I2S_FRAC_MAX_PRATE),
COMPOSITE_NOMUX(0, "i2s1_pre", "i2s_src", 0,
RK2928_CLKSEL_CON(3), 0, 7, DFLAGS,
RK2928_CLKGATE_CON(0), 9, GFLAGS),
COMPOSITE_FRACMUX(0, "i2s1_frac", "i2s1_pre", 0,
RK2928_CLKSEL_CON(7), 0,
RK2928_CLKGATE_CON(0), 10, GFLAGS,
- &rk3066a_i2s1_fracmux),
+ &rk3066a_i2s1_fracmux, RK3188_I2S_FRAC_MAX_PRATE),
COMPOSITE_NOMUX(0, "i2s2_pre", "i2s_src", 0,
RK2928_CLKSEL_CON(4), 0, 7, DFLAGS,
RK2928_CLKGATE_CON(0), 11, GFLAGS),
COMPOSITE_FRACMUX(0, "i2s2_frac", "i2s2_pre", 0,
RK2928_CLKSEL_CON(8), 0,
RK2928_CLKGATE_CON(0), 12, GFLAGS,
- &rk3066a_i2s2_fracmux),
+ &rk3066a_i2s2_fracmux, RK3188_I2S_FRAC_MAX_PRATE),
GATE(HCLK_I2S1, "hclk_i2s1", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 3, GFLAGS),
GATE(HCLK_I2S2, "hclk_i2s2", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 4, GFLAGS),
@@ -726,7 +730,7 @@ static struct rockchip_clk_branch rk3188_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "i2s0_frac", "i2s0_pre", CLK_SET_RATE_PARENT,
RK2928_CLKSEL_CON(7), 0,
RK2928_CLKGATE_CON(0), 10, GFLAGS,
- &rk3188_i2s0_fracmux),
+ &rk3188_i2s0_fracmux, RK3188_I2S_FRAC_MAX_PRATE),
GATE(0, "hclk_imem0", "hclk_cpu", 0, RK2928_CLKGATE_CON(4), 14, GFLAGS),
GATE(0, "hclk_imem1", "hclk_cpu", 0, RK2928_CLKGATE_CON(4), 15, GFLAGS),
diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c
index 47d6482dda9d..c1ef00247e26 100644
--- a/drivers/clk/rockchip/clk-rk3228.c
+++ b/drivers/clk/rockchip/clk-rk3228.c
@@ -15,6 +15,10 @@
#define RK3228_GRF_SOC_STATUS0 0x480
+#define RK3228_UART_FRAC_MAX_PRATE 600000000
+#define RK3228_SPDIF_FRAC_MAX_PRATE 600000000
+#define RK3228_I2S_FRAC_MAX_PRATE 600000000
+
enum rk3228_plls {
apll, dpll, cpll, gpll,
};
@@ -419,7 +423,7 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "i2s0_frac", "i2s0_src", CLK_SET_RATE_PARENT,
RK2928_CLKSEL_CON(8), 0,
RK2928_CLKGATE_CON(0), 4, GFLAGS,
- &rk3228_i2s0_fracmux),
+ &rk3228_i2s0_fracmux, RK3228_I2S_FRAC_MAX_PRATE),
GATE(SCLK_I2S0, "sclk_i2s0", "i2s0_pre", CLK_SET_RATE_PARENT,
RK2928_CLKGATE_CON(0), 5, GFLAGS),
@@ -429,7 +433,7 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "i2s1_frac", "i2s1_src", CLK_SET_RATE_PARENT,
RK2928_CLKSEL_CON(7), 0,
RK2928_CLKGATE_CON(0), 11, GFLAGS,
- &rk3228_i2s1_fracmux),
+ &rk3228_i2s1_fracmux, RK3228_I2S_FRAC_MAX_PRATE),
GATE(SCLK_I2S1, "sclk_i2s1", "i2s1_pre", CLK_SET_RATE_PARENT,
RK2928_CLKGATE_CON(0), 14, GFLAGS),
COMPOSITE_NODIV(SCLK_I2S_OUT, "i2s_out", mux_i2s_out_p, 0,
@@ -442,7 +446,7 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "i2s2_frac", "i2s2_src", CLK_SET_RATE_PARENT,
RK2928_CLKSEL_CON(30), 0,
RK2928_CLKGATE_CON(0), 8, GFLAGS,
- &rk3228_i2s2_fracmux),
+ &rk3228_i2s2_fracmux, RK3228_I2S_FRAC_MAX_PRATE),
GATE(SCLK_I2S2, "sclk_i2s2", "i2s2_pre", CLK_SET_RATE_PARENT,
RK2928_CLKGATE_CON(0), 9, GFLAGS),
@@ -452,7 +456,7 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "spdif_frac", "sclk_spdif_src", CLK_SET_RATE_PARENT,
RK2928_CLKSEL_CON(20), 0,
RK2928_CLKGATE_CON(2), 12, GFLAGS,
- &rk3228_spdif_fracmux),
+ &rk3228_spdif_fracmux, RK3228_SPDIF_FRAC_MAX_PRATE),
GATE(0, "jtag", "ext_jtag", CLK_IGNORE_UNUSED,
RK2928_CLKGATE_CON(1), 3, GFLAGS),
@@ -487,15 +491,15 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "uart0_frac", "uart0_src", CLK_SET_RATE_PARENT,
RK2928_CLKSEL_CON(17), 0,
RK2928_CLKGATE_CON(1), 9, GFLAGS,
- &rk3228_uart0_fracmux),
+ &rk3228_uart0_fracmux, RK3228_UART_FRAC_MAX_PRATE),
COMPOSITE_FRACMUX(0, "uart1_frac", "uart1_src", CLK_SET_RATE_PARENT,
RK2928_CLKSEL_CON(18), 0,
RK2928_CLKGATE_CON(1), 11, GFLAGS,
- &rk3228_uart1_fracmux),
+ &rk3228_uart1_fracmux, RK3228_UART_FRAC_MAX_PRATE),
COMPOSITE_FRACMUX(0, "uart2_frac", "uart2_src", CLK_SET_RATE_PARENT,
RK2928_CLKSEL_CON(19), 0,
RK2928_CLKGATE_CON(1), 13, GFLAGS,
- &rk3228_uart2_fracmux),
+ &rk3228_uart2_fracmux, RK3228_UART_FRAC_MAX_PRATE),
COMPOSITE(SCLK_NANDC, "sclk_nandc", mux_pll_src_2plls_p, 0,
RK2928_CLKSEL_CON(2), 14, 1, MFLAGS, 8, 5, DFLAGS,
diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c
index 93c794695c46..15c8f1dcba9a 100644
--- a/drivers/clk/rockchip/clk-rk3288.c
+++ b/drivers/clk/rockchip/clk-rk3288.c
@@ -14,6 +14,9 @@
#define RK3288_GRF_SOC_CON(x) (0x244 + x * 4)
#define RK3288_GRF_SOC_STATUS1 0x284
+#define RK3288_UART_FRAC_MAX_PRATE 600000000
+#define RK3288_I2S_FRAC_MAX_PRATE 600000000
+#define RK3288_SPDIF_FRAC_MAX_PRATE 600000000
enum rk3288_variant {
RK3288_CRU,
@@ -362,7 +365,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "i2s_frac", "i2s_src", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(8), 0,
RK3288_CLKGATE_CON(4), 2, GFLAGS,
- &rk3288_i2s_fracmux),
+ &rk3288_i2s_fracmux, RK3288_I2S_FRAC_MAX_PRATE),
COMPOSITE_NODIV(SCLK_I2S0_OUT, "i2s0_clkout", mux_i2s_clkout_p, 0,
RK3288_CLKSEL_CON(4), 12, 1, MFLAGS,
RK3288_CLKGATE_CON(4), 0, GFLAGS),
@@ -377,7 +380,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "spdif_frac", "spdif_src", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(9), 0,
RK3288_CLKGATE_CON(4), 5, GFLAGS,
- &rk3288_spdif_fracmux),
+ &rk3288_spdif_fracmux, RK3288_SPDIF_FRAC_MAX_PRATE),
GATE(SCLK_SPDIF, "sclk_spdif", "spdif_mux", CLK_SET_RATE_PARENT,
RK3288_CLKGATE_CON(4), 6, GFLAGS),
COMPOSITE_NOMUX(0, "spdif_8ch_pre", "spdif_src", CLK_SET_RATE_PARENT,
@@ -386,7 +389,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "spdif_8ch_frac", "spdif_8ch_pre", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(41), 0,
RK3288_CLKGATE_CON(4), 8, GFLAGS,
- &rk3288_spdif_8ch_fracmux),
+ &rk3288_spdif_8ch_fracmux, RK3288_SPDIF_FRAC_MAX_PRATE),
GATE(SCLK_SPDIF8CH, "sclk_spdif_8ch", "spdif_8ch_mux", CLK_SET_RATE_PARENT,
RK3288_CLKGATE_CON(4), 9, GFLAGS),
@@ -587,7 +590,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "uart0_frac", "uart0_src", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(17), 0,
RK3288_CLKGATE_CON(1), 9, GFLAGS,
- &rk3288_uart0_fracmux),
+ &rk3288_uart0_fracmux, RK3288_UART_FRAC_MAX_PRATE),
MUX(0, "uart_src", mux_pll_src_cpll_gpll_p, 0,
RK3288_CLKSEL_CON(13), 15, 1, MFLAGS),
COMPOSITE_NOMUX(0, "uart1_src", "uart_src", 0,
@@ -596,28 +599,28 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "uart1_frac", "uart1_src", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(18), 0,
RK3288_CLKGATE_CON(1), 11, GFLAGS,
- &rk3288_uart1_fracmux),
+ &rk3288_uart1_fracmux, RK3288_UART_FRAC_MAX_PRATE),
COMPOSITE_NOMUX(0, "uart2_src", "uart_src", 0,
RK3288_CLKSEL_CON(15), 0, 7, DFLAGS,
RK3288_CLKGATE_CON(1), 12, GFLAGS),
COMPOSITE_FRACMUX(0, "uart2_frac", "uart2_src", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(19), 0,
RK3288_CLKGATE_CON(1), 13, GFLAGS,
- &rk3288_uart2_fracmux),
+ &rk3288_uart2_fracmux, RK3288_UART_FRAC_MAX_PRATE),
COMPOSITE_NOMUX(0, "uart3_src", "uart_src", 0,
RK3288_CLKSEL_CON(16), 0, 7, DFLAGS,
RK3288_CLKGATE_CON(1), 14, GFLAGS),
COMPOSITE_FRACMUX(0, "uart3_frac", "uart3_src", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(20), 0,
RK3288_CLKGATE_CON(1), 15, GFLAGS,
- &rk3288_uart3_fracmux),
+ &rk3288_uart3_fracmux, RK3288_UART_FRAC_MAX_PRATE),
COMPOSITE_NOMUX(0, "uart4_src", "uart_src", 0,
RK3288_CLKSEL_CON(3), 0, 7, DFLAGS,
RK3288_CLKGATE_CON(2), 12, GFLAGS),
COMPOSITE_FRACMUX(0, "uart4_frac", "uart4_src", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(7), 0,
RK3288_CLKGATE_CON(2), 13, GFLAGS,
- &rk3288_uart4_fracmux),
+ &rk3288_uart4_fracmux, RK3288_UART_FRAC_MAX_PRATE),
COMPOSITE(0, "mac_pll_src", mux_pll_src_npll_cpll_gpll_p, 0,
RK3288_CLKSEL_CON(21), 0, 2, MFLAGS, 8, 5, DFLAGS,
diff --git a/drivers/clk/rockchip/clk-rk3308.c b/drivers/clk/rockchip/clk-rk3308.c
index 5bf15f2a44b7..f7cf9b61eec2 100644
--- a/drivers/clk/rockchip/clk-rk3308.c
+++ b/drivers/clk/rockchip/clk-rk3308.c
@@ -13,6 +13,12 @@
#include "clk.h"
#define RK3308_GRF_SOC_STATUS0 0x380
+#define RK3308_VOP_FRAC_MAX_PRATE 270000000
+#define RK3308B_VOP_FRAC_MAX_PRATE 800000000
+#define RK3308_UART_FRAC_MAX_PRATE 800000000
+#define RK3308_PDM_FRAC_MAX_PRATE 800000000
+#define RK3308_SPDIF_FRAC_MAX_PRATE 800000000
+#define RK3308_I2S_FRAC_MAX_PRATE 800000000
enum rk3308_plls {
apll, dpll, vpll0, vpll1,
@@ -332,7 +338,7 @@ static struct rockchip_clk_branch rk3308_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "clk_uart0_frac", "clk_uart0_src", CLK_SET_RATE_PARENT,
RK3308_CLKSEL_CON(12), 0,
RK3308_CLKGATE_CON(1), 11, GFLAGS,
- &rk3308_uart0_fracmux),
+ &rk3308_uart0_fracmux, RK3308_UART_FRAC_MAX_PRATE),
GATE(SCLK_UART0, "clk_uart0", "clk_uart0_mux", 0,
RK3308_CLKGATE_CON(1), 12, GFLAGS),
@@ -342,7 +348,7 @@ static struct rockchip_clk_branch rk3308_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "clk_uart1_frac", "clk_uart1_src", CLK_SET_RATE_PARENT,
RK3308_CLKSEL_CON(15), 0,
RK3308_CLKGATE_CON(1), 15, GFLAGS,
- &rk3308_uart1_fracmux),
+ &rk3308_uart1_fracmux, RK3308_UART_FRAC_MAX_PRATE),
GATE(SCLK_UART1, "clk_uart1", "clk_uart1_mux", 0,
RK3308_CLKGATE_CON(2), 0, GFLAGS),
@@ -352,7 +358,7 @@ static struct rockchip_clk_branch rk3308_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "clk_uart2_frac", "clk_uart2_src", CLK_SET_RATE_PARENT,
RK3308_CLKSEL_CON(18), 0,
RK3308_CLKGATE_CON(2), 3, GFLAGS,
- &rk3308_uart2_fracmux),
+ &rk3308_uart2_fracmux, RK3308_UART_FRAC_MAX_PRATE),
GATE(SCLK_UART2, "clk_uart2", "clk_uart2_mux", CLK_SET_RATE_PARENT,
RK3308_CLKGATE_CON(2), 4, GFLAGS),
@@ -362,7 +368,7 @@ static struct rockchip_clk_branch rk3308_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "clk_uart3_frac", "clk_uart3_src", CLK_SET_RATE_PARENT,
RK3308_CLKSEL_CON(21), 0,
RK3308_CLKGATE_CON(2), 7, GFLAGS,
- &rk3308_uart3_fracmux),
+ &rk3308_uart3_fracmux, RK3308_UART_FRAC_MAX_PRATE),
GATE(SCLK_UART3, "clk_uart3", "clk_uart3_mux", 0,
RK3308_CLKGATE_CON(2), 8, GFLAGS),
@@ -372,7 +378,7 @@ static struct rockchip_clk_branch rk3308_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "clk_uart4_frac", "clk_uart4_src", CLK_SET_RATE_PARENT,
RK3308_CLKSEL_CON(24), 0,
RK3308_CLKGATE_CON(2), 11, GFLAGS,
- &rk3308_uart4_fracmux),
+ &rk3308_uart4_fracmux, RK3308_UART_FRAC_MAX_PRATE),
GATE(SCLK_UART4, "clk_uart4", "clk_uart4_mux", 0,
RK3308_CLKGATE_CON(2), 12, GFLAGS),
@@ -452,7 +458,7 @@ static struct rockchip_clk_branch rk3308_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "dclk_vop_frac", "dclk_vop_src", CLK_SET_RATE_PARENT,
RK3308_CLKSEL_CON(9), 0,
RK3308_CLKGATE_CON(1), 7, GFLAGS,
- &rk3308_dclk_vop_fracmux),
+ &rk3308_dclk_vop_fracmux, RK3308B_VOP_FRAC_MAX_PRATE),
GATE(DCLK_VOP, "dclk_vop", "dclk_vop_mux", 0,
RK3308_CLKGATE_CON(1), 8, GFLAGS),
@@ -583,7 +589,7 @@ static struct rockchip_clk_branch rk3308_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "clk_rtc32k_frac", "xin24m", CLK_IGNORE_UNUSED,
RK3308_CLKSEL_CON(3), 0,
RK3308_CLKGATE_CON(4), 3, GFLAGS,
- &rk3308_rtc32k_fracmux),
+ &rk3308_rtc32k_fracmux, 0),
MUX(0, "clk_rtc32k_div_src", mux_vpll0_vpll1_p, 0,
RK3308_CLKSEL_CON(2), 10, 1, MFLAGS),
COMPOSITE_NOMUX(0, "clk_rtc32k_div", "clk_rtc32k_div_src", CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT,
@@ -633,7 +639,7 @@ static struct rockchip_clk_branch rk3308_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "clk_pdm_frac", "clk_pdm_src", CLK_SET_RATE_PARENT,
RK3308_CLKSEL_CON(47), 0,
RK3308_CLKGATE_CON(10), 4, GFLAGS,
- &rk3308_pdm_fracmux),
+ &rk3308_pdm_fracmux, RK3308_PDM_FRAC_MAX_PRATE),
GATE(SCLK_PDM, "clk_pdm", "clk_pdm_mux", 0,
RK3308_CLKGATE_CON(10), 5, GFLAGS),
@@ -643,7 +649,7 @@ static struct rockchip_clk_branch rk3308_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "clk_i2s0_8ch_tx_frac", "clk_i2s0_8ch_tx_src", CLK_SET_RATE_PARENT,
RK3308_CLKSEL_CON(53), 0,
RK3308_CLKGATE_CON(10), 13, GFLAGS,
- &rk3308_i2s0_8ch_tx_fracmux),
+ &rk3308_i2s0_8ch_tx_fracmux, RK3308_I2S_FRAC_MAX_PRATE),
COMPOSITE_NODIV(SCLK_I2S0_8CH_TX, "clk_i2s0_8ch_tx", mux_i2s0_8ch_tx_rx_p, CLK_SET_RATE_PARENT,
RK3308_CLKSEL_CON(52), 12, 1, MFLAGS,
RK3308_CLKGATE_CON(10), 14, GFLAGS),
@@ -657,7 +663,7 @@ static struct rockchip_clk_branch rk3308_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "clk_i2s0_8ch_rx_frac", "clk_i2s0_8ch_rx_src", CLK_SET_RATE_PARENT,
RK3308_CLKSEL_CON(55), 0,
RK3308_CLKGATE_CON(11), 1, GFLAGS,
- &rk3308_i2s0_8ch_rx_fracmux),
+ &rk3308_i2s0_8ch_rx_fracmux, RK3308_I2S_FRAC_MAX_PRATE),
COMPOSITE_NODIV(SCLK_I2S0_8CH_RX, "clk_i2s0_8ch_rx", mux_i2s0_8ch_rx_tx_p, CLK_SET_RATE_PARENT,
RK3308_CLKSEL_CON(54), 12, 1, MFLAGS,
RK3308_CLKGATE_CON(11), 2, GFLAGS),
@@ -670,7 +676,7 @@ static struct rockchip_clk_branch rk3308_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "clk_i2s1_8ch_tx_frac", "clk_i2s1_8ch_tx_src", CLK_SET_RATE_PARENT,
RK3308_CLKSEL_CON(57), 0,
RK3308_CLKGATE_CON(11), 5, GFLAGS,
- &rk3308_i2s1_8ch_tx_fracmux),
+ &rk3308_i2s1_8ch_tx_fracmux, RK3308_I2S_FRAC_MAX_PRATE),
COMPOSITE_NODIV(SCLK_I2S1_8CH_TX, "clk_i2s1_8ch_tx", mux_i2s1_8ch_tx_rx_p, CLK_SET_RATE_PARENT,
RK3308_CLKSEL_CON(56), 12, 1, MFLAGS,
RK3308_CLKGATE_CON(11), 6, GFLAGS),
@@ -684,7 +690,7 @@ static struct rockchip_clk_branch rk3308_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "clk_i2s1_8ch_rx_frac", "clk_i2s1_8ch_rx_src", CLK_SET_RATE_PARENT,
RK3308_CLKSEL_CON(59), 0,
RK3308_CLKGATE_CON(11), 9, GFLAGS,
- &rk3308_i2s1_8ch_rx_fracmux),
+ &rk3308_i2s1_8ch_rx_fracmux, RK3308_I2S_FRAC_MAX_PRATE),
COMPOSITE_NODIV(SCLK_I2S1_8CH_RX, "clk_i2s1_8ch_rx", mux_i2s1_8ch_rx_tx_p, CLK_SET_RATE_PARENT,
RK3308_CLKSEL_CON(58), 12, 1, MFLAGS,
RK3308_CLKGATE_CON(11), 10, GFLAGS),
@@ -697,7 +703,7 @@ static struct rockchip_clk_branch rk3308_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "clk_i2s2_8ch_tx_frac", "clk_i2s2_8ch_tx_src", CLK_SET_RATE_PARENT,
RK3308_CLKSEL_CON(61), 0,
RK3308_CLKGATE_CON(11), 13, GFLAGS,
- &rk3308_i2s2_8ch_tx_fracmux),
+ &rk3308_i2s2_8ch_tx_fracmux, RK3308_I2S_FRAC_MAX_PRATE),
COMPOSITE_NODIV(SCLK_I2S2_8CH_TX, "clk_i2s2_8ch_tx", mux_i2s2_8ch_tx_rx_p, CLK_SET_RATE_PARENT,
RK3308_CLKSEL_CON(60), 12, 1, MFLAGS,
RK3308_CLKGATE_CON(11), 14, GFLAGS),
@@ -711,7 +717,7 @@ static struct rockchip_clk_branch rk3308_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "clk_i2s2_8ch_rx_frac", "clk_i2s2_8ch_rx_src", CLK_SET_RATE_PARENT,
RK3308_CLKSEL_CON(63), 0,
RK3308_CLKGATE_CON(12), 1, GFLAGS,
- &rk3308_i2s2_8ch_rx_fracmux),
+ &rk3308_i2s2_8ch_rx_fracmux, RK3308_I2S_FRAC_MAX_PRATE),
COMPOSITE_NODIV(SCLK_I2S2_8CH_RX, "clk_i2s2_8ch_rx", mux_i2s2_8ch_rx_tx_p, CLK_SET_RATE_PARENT,
RK3308_CLKSEL_CON(62), 12, 1, MFLAGS,
RK3308_CLKGATE_CON(12), 2, GFLAGS),
@@ -724,7 +730,7 @@ static struct rockchip_clk_branch rk3308_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "clk_i2s3_8ch_tx_frac", "clk_i2s3_8ch_tx_src", CLK_SET_RATE_PARENT,
RK3308_CLKSEL_CON(65), 0,
RK3308_CLKGATE_CON(12), 5, GFLAGS,
- &rk3308_i2s3_8ch_tx_fracmux),
+ &rk3308_i2s3_8ch_tx_fracmux, RK3308_I2S_FRAC_MAX_PRATE),
COMPOSITE_NODIV(SCLK_I2S3_8CH_TX, "clk_i2s3_8ch_tx", mux_i2s3_8ch_tx_rx_p, CLK_SET_RATE_PARENT,
RK3308_CLKSEL_CON(64), 12, 1, MFLAGS,
RK3308_CLKGATE_CON(12), 6, GFLAGS),
@@ -738,7 +744,7 @@ static struct rockchip_clk_branch rk3308_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "clk_i2s3_8ch_rx_frac", "clk_i2s3_8ch_rx_src", CLK_SET_RATE_PARENT,
RK3308_CLKSEL_CON(67), 0,
RK3308_CLKGATE_CON(12), 9, GFLAGS,
- &rk3308_i2s3_8ch_rx_fracmux),
+ &rk3308_i2s3_8ch_rx_fracmux, RK3308_I2S_FRAC_MAX_PRATE),
COMPOSITE_NODIV(SCLK_I2S3_8CH_RX, "clk_i2s3_8ch_rx", mux_i2s3_8ch_rx_tx_p, CLK_SET_RATE_PARENT,
RK3308_CLKSEL_CON(66), 12, 1, MFLAGS,
RK3308_CLKGATE_CON(12), 10, GFLAGS),
@@ -751,7 +757,7 @@ static struct rockchip_clk_branch rk3308_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "clk_i2s0_2ch_frac", "clk_i2s0_2ch_src", CLK_SET_RATE_PARENT,
RK3308_CLKSEL_CON(69), 0,
RK3308_CLKGATE_CON(12), 13, GFLAGS,
- &rk3308_i2s0_2ch_fracmux),
+ &rk3308_i2s0_2ch_fracmux, RK3308_I2S_FRAC_MAX_PRATE),
GATE(SCLK_I2S0_2CH, "clk_i2s0_2ch", "clk_i2s0_2ch_mux", 0,
RK3308_CLKGATE_CON(12), 14, GFLAGS),
COMPOSITE_NODIV(SCLK_I2S0_2CH_OUT, "clk_i2s0_2ch_out", mux_i2s0_2ch_out_p, CLK_SET_RATE_PARENT,
@@ -764,7 +770,7 @@ static struct rockchip_clk_branch rk3308_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "clk_i2s1_2ch_frac", "clk_i2s1_2ch_src", CLK_SET_RATE_PARENT,
RK3308_CLKSEL_CON(71), 0,
RK3308_CLKGATE_CON(13), 1, GFLAGS,
- &rk3308_i2s1_2ch_fracmux),
+ &rk3308_i2s1_2ch_fracmux, RK3308_I2S_FRAC_MAX_PRATE),
GATE(SCLK_I2S1_2CH, "clk_i2s1_2ch", "clk_i2s1_2ch_mux", 0,
RK3308_CLKGATE_CON(13), 2, GFLAGS),
COMPOSITE_NODIV(SCLK_I2S1_2CH_OUT, "clk_i2s1_2ch_out", mux_i2s1_2ch_out_p, CLK_SET_RATE_PARENT,
@@ -782,7 +788,7 @@ static struct rockchip_clk_branch rk3308_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "clk_spdif_tx_frac", "clk_spdif_tx_src", CLK_SET_RATE_PARENT,
RK3308_CLKSEL_CON(49), 0,
RK3308_CLKGATE_CON(10), 7, GFLAGS,
- &rk3308_spdif_tx_fracmux),
+ &rk3308_spdif_tx_fracmux, RK3308_SPDIF_FRAC_MAX_PRATE),
GATE(SCLK_SPDIF_TX, "clk_spdif_tx", "clk_spdif_tx_mux", 0,
RK3308_CLKGATE_CON(10), 8, GFLAGS),
@@ -797,7 +803,7 @@ static struct rockchip_clk_branch rk3308_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "clk_spdif_rx_frac", "clk_spdif_rx_src", CLK_SET_RATE_PARENT,
RK3308_CLKSEL_CON(51), 0,
RK3308_CLKGATE_CON(10), 10, GFLAGS,
- &rk3308_spdif_rx_fracmux),
+ &rk3308_spdif_rx_fracmux, RK3308_SPDIF_FRAC_MAX_PRATE),
GATE(SCLK_SPDIF_RX, "clk_spdif_rx", "clk_spdif_rx_mux", 0,
RK3308_CLKGATE_CON(10), 11, GFLAGS),
diff --git a/drivers/clk/rockchip/clk-rk3328.c b/drivers/clk/rockchip/clk-rk3328.c
index 2429b7c2a8b3..cc18dbc18ae8 100644
--- a/drivers/clk/rockchip/clk-rk3328.c
+++ b/drivers/clk/rockchip/clk-rk3328.c
@@ -16,6 +16,9 @@
#define RK3328_GRF_SOC_STATUS0 0x480
#define RK3328_GRF_MAC_CON1 0x904
#define RK3328_GRF_MAC_CON2 0x908
+#define RK3328_I2S_FRAC_MAX_PRATE 600000000
+#define RK3328_UART_FRAC_MAX_PRATE 600000000
+#define RK3328_SPDIF_FRAC_MAX_PRATE 600000000
enum rk3328_plls {
apll, dpll, cpll, gpll, npll,
@@ -372,7 +375,7 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
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),
+ &rk3328_i2s0_fracmux, RK3328_I2S_FRAC_MAX_PRATE),
GATE(SCLK_I2S0, "clk_i2s0", "i2s0_pre", CLK_SET_RATE_PARENT,
RK3328_CLKGATE_CON(1), 3, GFLAGS),
@@ -382,7 +385,7 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
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),
+ &rk3328_i2s1_fracmux, RK3328_I2S_FRAC_MAX_PRATE),
GATE(SCLK_I2S1, "clk_i2s1", "i2s1_pre", CLK_SET_RATE_PARENT,
RK3328_CLKGATE_CON(1), 6, GFLAGS),
COMPOSITE_NODIV(SCLK_I2S1_OUT, "i2s1_out", mux_i2s1out_p, 0,
@@ -395,7 +398,7 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
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),
+ &rk3328_i2s2_fracmux, RK3328_I2S_FRAC_MAX_PRATE),
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,
@@ -408,7 +411,7 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
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),
+ &rk3328_spdif_fracmux, RK3328_SPDIF_FRAC_MAX_PRATE),
/* PD_UART */
COMPOSITE(0, "clk_uart0_div", mux_2plls_u480m_p, 0,
@@ -423,15 +426,15 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
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),
+ &rk3328_uart0_fracmux, RK3328_UART_FRAC_MAX_PRATE),
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),
+ &rk3328_uart1_fracmux, RK3328_UART_FRAC_MAX_PRATE),
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),
+ &rk3328_uart2_fracmux, RK3328_UART_FRAC_MAX_PRATE),
/*
* Clock-Architecture Diagram 4
diff --git a/drivers/clk/rockchip/clk-rk3368.c b/drivers/clk/rockchip/clk-rk3368.c
index 55443349439b..d20e51dabb63 100644
--- a/drivers/clk/rockchip/clk-rk3368.c
+++ b/drivers/clk/rockchip/clk-rk3368.c
@@ -12,6 +12,9 @@
#include "clk.h"
#define RK3368_GRF_SOC_STATUS0 0x480
+#define RK3368_I2S_FRAC_MAX_PRATE 600000000
+#define RK3368_UART_FRAC_MAX_PRATE 600000000
+#define RK3368_SPDIF_FRAC_MAX_PRATE 600000000
enum rk3368_plls {
apllb, aplll, dpll, cpll, gpll, npll,
@@ -368,7 +371,7 @@ static struct rockchip_clk_branch rk3368_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "i2s_8ch_frac", "i2s_8ch_src", CLK_SET_RATE_PARENT,
RK3368_CLKSEL_CON(28), 0,
RK3368_CLKGATE_CON(6), 2, GFLAGS,
- &rk3368_i2s_8ch_fracmux),
+ &rk3368_i2s_8ch_fracmux, RK3368_I2S_FRAC_MAX_PRATE),
COMPOSITE_NODIV(SCLK_I2S_8CH_OUT, "i2s_8ch_clkout", mux_i2s_8ch_clkout_p, 0,
RK3368_CLKSEL_CON(27), 15, 1, MFLAGS,
RK3368_CLKGATE_CON(6), 0, GFLAGS),
@@ -380,7 +383,7 @@ static struct rockchip_clk_branch rk3368_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "spdif_8ch_frac", "spdif_8ch_src", CLK_SET_RATE_PARENT,
RK3368_CLKSEL_CON(32), 0,
RK3368_CLKGATE_CON(6), 5, GFLAGS,
- &rk3368_spdif_8ch_fracmux),
+ &rk3368_spdif_8ch_fracmux, RK3368_SPDIF_FRAC_MAX_PRATE),
GATE(SCLK_SPDIF_8CH, "sclk_spdif_8ch", "spdif_8ch_pre", CLK_SET_RATE_PARENT,
RK3368_CLKGATE_CON(6), 6, GFLAGS),
COMPOSITE(0, "i2s_2ch_src", mux_pll_src_cpll_gpll_p, 0,
@@ -389,7 +392,7 @@ static struct rockchip_clk_branch rk3368_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "i2s_2ch_frac", "i2s_2ch_src", CLK_SET_RATE_PARENT,
RK3368_CLKSEL_CON(54), 0,
RK3368_CLKGATE_CON(5), 14, GFLAGS,
- &rk3368_i2s_2ch_fracmux),
+ &rk3368_i2s_2ch_fracmux, RK3368_I2S_FRAC_MAX_PRATE),
GATE(SCLK_I2S_2CH, "sclk_i2s_2ch", "i2s_2ch_pre", CLK_SET_RATE_PARENT,
RK3368_CLKGATE_CON(5), 15, GFLAGS),
@@ -590,7 +593,7 @@ static struct rockchip_clk_branch rk3368_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "uart0_frac", "uart0_src", CLK_SET_RATE_PARENT,
RK3368_CLKSEL_CON(34), 0,
RK3368_CLKGATE_CON(2), 1, GFLAGS,
- &rk3368_uart0_fracmux),
+ &rk3368_uart0_fracmux, RK3368_UART_FRAC_MAX_PRATE),
COMPOSITE_NOMUX(0, "uart1_src", "uart_src", 0,
RK3368_CLKSEL_CON(35), 0, 7, DFLAGS,
@@ -598,7 +601,7 @@ static struct rockchip_clk_branch rk3368_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "uart1_frac", "uart1_src", CLK_SET_RATE_PARENT,
RK3368_CLKSEL_CON(36), 0,
RK3368_CLKGATE_CON(2), 3, GFLAGS,
- &rk3368_uart1_fracmux),
+ &rk3368_uart1_fracmux, RK3368_UART_FRAC_MAX_PRATE),
COMPOSITE_NOMUX(0, "uart3_src", "uart_src", 0,
RK3368_CLKSEL_CON(39), 0, 7, DFLAGS,
@@ -606,7 +609,7 @@ static struct rockchip_clk_branch rk3368_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "uart3_frac", "uart3_src", CLK_SET_RATE_PARENT,
RK3368_CLKSEL_CON(40), 0,
RK3368_CLKGATE_CON(2), 7, GFLAGS,
- &rk3368_uart3_fracmux),
+ &rk3368_uart3_fracmux, RK3368_UART_FRAC_MAX_PRATE),
COMPOSITE_NOMUX(0, "uart4_src", "uart_src", 0,
RK3368_CLKSEL_CON(41), 0, 7, DFLAGS,
@@ -614,7 +617,7 @@ static struct rockchip_clk_branch rk3368_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "uart4_frac", "uart4_src", CLK_SET_RATE_PARENT,
RK3368_CLKSEL_CON(42), 0,
RK3368_CLKGATE_CON(2), 9, GFLAGS,
- &rk3368_uart4_fracmux),
+ &rk3368_uart4_fracmux, RK3368_UART_FRAC_MAX_PRATE),
COMPOSITE(0, "mac_pll_src", mux_pll_src_npll_cpll_gpll_p, 0,
RK3368_CLKSEL_CON(43), 6, 2, MFLAGS, 0, 5, DFLAGS,
diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c
index 7df2f1e00347..3682d5675cf7 100644
--- a/drivers/clk/rockchip/clk-rk3399.c
+++ b/drivers/clk/rockchip/clk-rk3399.c
@@ -15,6 +15,12 @@
#include <dt-bindings/clock/rk3399-cru.h>
#include "clk.h"
+#define RK3399_I2S_FRAC_MAX_PRATE 800000000
+#define RK3399_UART_FRAC_MAX_PRATE 800000000
+#define RK3399_SPDIF_FRAC_MAX_PRATE 600000000
+#define RK3399_VOP_FRAC_MAX_PRATE 600000000
+#define RK3399_WIFI_FRAC_MAX_PRATE 600000000
+
enum rk3399_plls {
lpll, bpll, dpll, cpll, gpll, npll, vpll,
};
@@ -584,7 +590,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "clk_spdif_frac", "clk_spdif_div", 0,
RK3399_CLKSEL_CON(99), 0,
RK3399_CLKGATE_CON(8), 14, GFLAGS,
- &rk3399_spdif_fracmux),
+ &rk3399_spdif_fracmux, RK3399_SPDIF_FRAC_MAX_PRATE),
GATE(SCLK_SPDIF_8CH, "clk_spdif", "clk_spdif_mux", CLK_SET_RATE_PARENT,
RK3399_CLKGATE_CON(8), 15, GFLAGS),
@@ -598,7 +604,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "clk_i2s0_frac", "clk_i2s0_div", 0,
RK3399_CLKSEL_CON(96), 0,
RK3399_CLKGATE_CON(8), 4, GFLAGS,
- &rk3399_i2s0_fracmux),
+ &rk3399_i2s0_fracmux, RK3399_I2S_FRAC_MAX_PRATE),
GATE(SCLK_I2S0_8CH, "clk_i2s0", "clk_i2s0_mux", CLK_SET_RATE_PARENT,
RK3399_CLKGATE_CON(8), 5, GFLAGS),
@@ -608,7 +614,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "clk_i2s1_frac", "clk_i2s1_div", 0,
RK3399_CLKSEL_CON(97), 0,
RK3399_CLKGATE_CON(8), 7, GFLAGS,
- &rk3399_i2s1_fracmux),
+ &rk3399_i2s1_fracmux, RK3399_I2S_FRAC_MAX_PRATE),
GATE(SCLK_I2S1_8CH, "clk_i2s1", "clk_i2s1_mux", CLK_SET_RATE_PARENT,
RK3399_CLKGATE_CON(8), 8, GFLAGS),
@@ -618,7 +624,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "clk_i2s2_frac", "clk_i2s2_div", 0,
RK3399_CLKSEL_CON(98), 0,
RK3399_CLKGATE_CON(8), 10, GFLAGS,
- &rk3399_i2s2_fracmux),
+ &rk3399_i2s2_fracmux, RK3399_I2S_FRAC_MAX_PRATE),
GATE(SCLK_I2S2_8CH, "clk_i2s2", "clk_i2s2_mux", CLK_SET_RATE_PARENT,
RK3399_CLKGATE_CON(8), 11, GFLAGS),
@@ -637,7 +643,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "clk_uart0_frac", "clk_uart0_div", 0,
RK3399_CLKSEL_CON(100), 0,
RK3399_CLKGATE_CON(9), 1, GFLAGS,
- &rk3399_uart0_fracmux),
+ &rk3399_uart0_fracmux, RK3399_UART_FRAC_MAX_PRATE),
MUX(0, "clk_uart_src", mux_pll_src_cpll_gpll_p, 0,
RK3399_CLKSEL_CON(33), 15, 1, MFLAGS),
@@ -647,7 +653,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "clk_uart1_frac", "clk_uart1_div", 0,
RK3399_CLKSEL_CON(101), 0,
RK3399_CLKGATE_CON(9), 3, GFLAGS,
- &rk3399_uart1_fracmux),
+ &rk3399_uart1_fracmux, RK3399_UART_FRAC_MAX_PRATE),
COMPOSITE_NOMUX(0, "clk_uart2_div", "clk_uart_src", 0,
RK3399_CLKSEL_CON(35), 0, 7, DFLAGS,
@@ -655,7 +661,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "clk_uart2_frac", "clk_uart2_div", 0,
RK3399_CLKSEL_CON(102), 0,
RK3399_CLKGATE_CON(9), 5, GFLAGS,
- &rk3399_uart2_fracmux),
+ &rk3399_uart2_fracmux, RK3399_UART_FRAC_MAX_PRATE),
COMPOSITE_NOMUX(0, "clk_uart3_div", "clk_uart_src", 0,
RK3399_CLKSEL_CON(36), 0, 7, DFLAGS,
@@ -663,7 +669,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "clk_uart3_frac", "clk_uart3_div", 0,
RK3399_CLKSEL_CON(103), 0,
RK3399_CLKGATE_CON(9), 7, GFLAGS,
- &rk3399_uart3_fracmux),
+ &rk3399_uart3_fracmux, RK3399_UART_FRAC_MAX_PRATE),
COMPOSITE(PCLK_DDR, "pclk_ddr", mux_pll_src_cpll_gpll_p, CLK_IGNORE_UNUSED,
RK3399_CLKSEL_CON(6), 15, 1, MFLAGS, 8, 5, DFLAGS,
@@ -1166,7 +1172,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {
COMPOSITE_FRACMUX_NOGATE(DCLK_VOP0_FRAC, "dclk_vop0_frac", "dclk_vop0_div", 0,
RK3399_CLKSEL_CON(106), 0,
- &rk3399_dclk_vop0_fracmux),
+ &rk3399_dclk_vop0_fracmux, RK3399_VOP_FRAC_MAX_PRATE),
COMPOSITE(SCLK_VOP0_PWM, "clk_vop0_pwm", mux_pll_src_vpll_cpll_gpll_24m_p, 0,
RK3399_CLKSEL_CON(51), 6, 2, MFLAGS, 0, 5, DFLAGS,
@@ -1196,7 +1202,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {
COMPOSITE_FRACMUX_NOGATE(DCLK_VOP1_FRAC, "dclk_vop1_frac", "dclk_vop1_div", 0,
RK3399_CLKSEL_CON(107), 0,
- &rk3399_dclk_vop1_fracmux),
+ &rk3399_dclk_vop1_fracmux, RK3399_VOP_FRAC_MAX_PRATE),
COMPOSITE(SCLK_VOP1_PWM, "clk_vop1_pwm", mux_pll_src_vpll_cpll_gpll_24m_p, CLK_IGNORE_UNUSED,
RK3399_CLKSEL_CON(52), 6, 2, MFLAGS, 0, 5, DFLAGS,
@@ -1313,7 +1319,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {
RK3399_CLKSEL_CON(58), 7, 1, MFLAGS),
COMPOSITE_FRAC(0, "clk_test_frac", "clk_test_pre", 0,
RK3399_CLKSEL_CON(105), 0,
- RK3399_CLKGATE_CON(13), 9, GFLAGS),
+ RK3399_CLKGATE_CON(13), 9, GFLAGS, 0),
DIV(0, "clk_test_24m", "xin24m", 0,
RK3399_CLKSEL_CON(57), 6, 10, DFLAGS),
@@ -1418,7 +1424,7 @@ static struct rockchip_clk_branch rk3399_clk_pmu_branches[] __initdata = {
COMPOSITE_FRACMUX_NOGATE(0, "clk_wifi_frac", "clk_wifi_div", 0,
RK3399_PMU_CLKSEL_CON(7), 0,
- &rk3399_pmuclk_wifi_fracmux),
+ &rk3399_pmuclk_wifi_fracmux, RK3399_WIFI_FRAC_MAX_PRATE),
MUX(0, "clk_timer_src_pmu", mux_pll_p, CLK_IGNORE_UNUSED,
RK3399_PMU_CLKSEL_CON(1), 15, 1, MFLAGS),
@@ -1447,7 +1453,7 @@ static struct rockchip_clk_branch rk3399_clk_pmu_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "clk_uart4_frac", "clk_uart4_div", 0,
RK3399_PMU_CLKSEL_CON(6), 0,
RK3399_PMU_CLKGATE_CON(0), 6, GFLAGS,
- &rk3399_uart4_pmu_fracmux),
+ &rk3399_uart4_pmu_fracmux, RK3399_UART_FRAC_MAX_PRATE),
DIV(PCLK_SRC_PMU, "pclk_pmu_src", "ppll", CLK_IGNORE_UNUSED,
RK3399_PMU_CLKSEL_CON(0), 0, 5, DFLAGS),
diff --git a/drivers/clk/rockchip/clk-rv1108.c b/drivers/clk/rockchip/clk-rv1108.c
index 5947d3192866..04b7f1161942 100644
--- a/drivers/clk/rockchip/clk-rv1108.c
+++ b/drivers/clk/rockchip/clk-rv1108.c
@@ -14,6 +14,8 @@
#include "clk.h"
#define RV1108_GRF_SOC_STATUS0 0x480
+#define RV1108_I2S_FRAC_MAX_RATE 600000000
+#define RV1108_UART_FRAC_MAX_RATE 600000000
enum rv1108_plls {
apll, dpll, gpll,
@@ -503,7 +505,7 @@ static struct rockchip_clk_branch rv1108_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "i2s0_frac", "i2s0_src", CLK_SET_RATE_PARENT,
RV1108_CLKSEL_CON(8), 0,
RV1108_CLKGATE_CON(2), 1, GFLAGS,
- &rv1108_i2s0_fracmux),
+ &rv1108_i2s0_fracmux, RV1108_I2S_FRAC_MAX_RATE),
GATE(SCLK_I2S0, "sclk_i2s0", "i2s0_pre", CLK_SET_RATE_PARENT,
RV1108_CLKGATE_CON(2), 2, GFLAGS),
COMPOSITE_NODIV(0, "i2s_out", mux_i2s_out_p, 0,
@@ -516,7 +518,7 @@ static struct rockchip_clk_branch rv1108_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "i2s1_frac", "i2s1_src", CLK_SET_RATE_PARENT,
RK2928_CLKSEL_CON(9), 0,
RK2928_CLKGATE_CON(2), 5, GFLAGS,
- &rv1108_i2s1_fracmux),
+ &rv1108_i2s1_fracmux, RV1108_I2S_FRAC_MAX_RATE),
GATE(SCLK_I2S1, "sclk_i2s1", "i2s1_pre", CLK_SET_RATE_PARENT,
RV1108_CLKGATE_CON(2), 6, GFLAGS),
@@ -526,7 +528,7 @@ static struct rockchip_clk_branch rv1108_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "i2s2_frac", "i2s2_src", CLK_SET_RATE_PARENT,
RV1108_CLKSEL_CON(10), 0,
RV1108_CLKGATE_CON(2), 9, GFLAGS,
- &rv1108_i2s2_fracmux),
+ &rv1108_i2s2_fracmux, RV1108_I2S_FRAC_MAX_RATE),
GATE(SCLK_I2S2, "sclk_i2s2", "i2s2_pre", CLK_SET_RATE_PARENT,
RV1108_CLKGATE_CON(2), 10, GFLAGS),
@@ -592,15 +594,15 @@ static struct rockchip_clk_branch rv1108_clk_branches[] __initdata = {
COMPOSITE_FRACMUX(0, "uart0_frac", "uart0_src", CLK_SET_RATE_PARENT,
RV1108_CLKSEL_CON(16), 0,
RV1108_CLKGATE_CON(3), 2, GFLAGS,
- &rv1108_uart0_fracmux),
+ &rv1108_uart0_fracmux, RV1108_UART_FRAC_MAX_RATE),
COMPOSITE_FRACMUX(0, "uart1_frac", "uart1_src", CLK_SET_RATE_PARENT,
RV1108_CLKSEL_CON(17), 0,
RV1108_CLKGATE_CON(3), 4, GFLAGS,
- &rv1108_uart1_fracmux),
+ &rv1108_uart1_fracmux, RV1108_UART_FRAC_MAX_RATE),
COMPOSITE_FRACMUX(0, "uart2_frac", "uart2_src", CLK_SET_RATE_PARENT,
RV1108_CLKSEL_CON(18), 0,
RV1108_CLKGATE_CON(3), 6, GFLAGS,
- &rv1108_uart2_fracmux),
+ &rv1108_uart2_fracmux, RV1108_UART_FRAC_MAX_RATE),
GATE(PCLK_UART0, "pclk_uart0", "pclk_bus_pre", 0,
RV1108_CLKGATE_CON(13), 10, GFLAGS),
GATE(PCLK_UART1, "pclk_uart1", "pclk_bus_pre", 0,
diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c
index b443169dd408..9d56a93e854c 100644
--- a/drivers/clk/rockchip/clk.c
+++ b/drivers/clk/rockchip/clk.c
@@ -182,12 +182,26 @@ static void rockchip_fractional_approximation(struct clk_hw *hw,
unsigned long p_rate, p_parent_rate;
struct clk_hw *p_parent;
unsigned long scale;
+ u32 div;
p_rate = clk_hw_get_rate(clk_hw_get_parent(hw));
- if ((rate * 20 > p_rate) && (p_rate % rate != 0)) {
+ if (((rate * 20 > p_rate) && (p_rate % rate != 0)) ||
+ (fd->max_prate && fd->max_prate < p_rate)) {
p_parent = clk_hw_get_parent(clk_hw_get_parent(hw));
p_parent_rate = clk_hw_get_rate(p_parent);
*parent_rate = p_parent_rate;
+ if (fd->max_prate && p_parent_rate > fd->max_prate) {
+ div = DIV_ROUND_UP(p_parent_rate, fd->max_prate);
+ *parent_rate = p_parent_rate / div;
+ }
+
+ if (*parent_rate < rate * 20) {
+ pr_err("%s parent_rate(%ld) is low than rate(%ld)*20, fractional div is not allowed\n",
+ clk_hw_get_name(hw), *parent_rate, rate);
+ *m = 0;
+ *n = 1;
+ return;
+ }
}
/*
@@ -210,7 +224,7 @@ static struct clk *rockchip_clk_register_frac_branch(
void __iomem *base, int muxdiv_offset, u8 div_flags,
int gate_offset, u8 gate_shift, u8 gate_flags,
unsigned long flags, struct rockchip_clk_branch *child,
- spinlock_t *lock)
+ unsigned long max_prate, spinlock_t *lock)
{
struct clk_hw *hw;
struct rockchip_clk_frac *frac;
@@ -251,6 +265,7 @@ static struct clk *rockchip_clk_register_frac_branch(
div->nmask = GENMASK(div->nwidth - 1, 0) << div->nshift;
div->lock = lock;
div->approximation = rockchip_fractional_approximation;
+ div->max_prate = max_prate;
div_ops = &clk_fractional_divider_ops;
hw = clk_hw_register_composite(NULL, name, parent_names, num_parents,
@@ -488,7 +503,7 @@ void rockchip_clk_register_branches(struct rockchip_clk_provider *ctx,
list->div_flags,
list->gate_offset, list->gate_shift,
list->gate_flags, flags, list->child,
- &ctx->lock);
+ list->max_prate, &ctx->lock);
break;
case branch_half_divider:
clk = rockchip_clk_register_halfdiv(list->name,
diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h
index 2271a84124b0..0d401ce09a54 100644
--- a/drivers/clk/rockchip/clk.h
+++ b/drivers/clk/rockchip/clk.h
@@ -420,6 +420,7 @@ struct rockchip_clk_branch {
u8 gate_shift;
u8 gate_flags;
struct rockchip_clk_branch *child;
+ unsigned long max_prate;
};
#define COMPOSITE(_id, cname, pnames, f, mo, ms, mw, mf, ds, dw,\
@@ -559,7 +560,7 @@ struct rockchip_clk_branch {
.gate_offset = -1, \
}
-#define COMPOSITE_FRAC(_id, cname, pname, f, mo, df, go, gs, gf)\
+#define COMPOSITE_FRAC(_id, cname, pname, f, mo, df, go, gs, gf, prate)\
{ \
.id = _id, \
.branch_type = branch_fraction_divider, \
@@ -574,9 +575,10 @@ struct rockchip_clk_branch {
.gate_offset = go, \
.gate_shift = gs, \
.gate_flags = gf, \
+ .max_prate = prate, \
}
-#define COMPOSITE_FRACMUX(_id, cname, pname, f, mo, df, go, gs, gf, ch) \
+#define COMPOSITE_FRACMUX(_id, cname, pname, f, mo, df, go, gs, gf, ch, prate) \
{ \
.id = _id, \
.branch_type = branch_fraction_divider, \
@@ -592,9 +594,10 @@ struct rockchip_clk_branch {
.gate_shift = gs, \
.gate_flags = gf, \
.child = ch, \
+ .max_prate = prate, \
}
-#define COMPOSITE_FRACMUX_NOGATE(_id, cname, pname, f, mo, df, ch) \
+#define COMPOSITE_FRACMUX_NOGATE(_id, cname, pname, f, mo, df, ch, prate) \
{ \
.id = _id, \
.branch_type = branch_fraction_divider, \
@@ -608,6 +611,7 @@ struct rockchip_clk_branch {
.div_flags = df, \
.gate_offset = -1, \
.child = ch, \
+ .max_prate = prate, \
}
#define COMPOSITE_DDRCLK(_id, cname, pnames, f, mo, ms, mw, \
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 03a5de5f99f4..b6b28a097526 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -924,6 +924,7 @@ void clk_hw_unregister_fixed_factor(struct clk_hw *hw);
* @mwidth: width of the numerator bit field
* @nshift: shift to the denominator bit field
* @nwidth: width of the denominator bit field
+ * @max_parent: the maximum frequency of fractional divider parent clock
* @lock: register lock
*
* Clock with adjustable fractional divider affecting its output frequency.
@@ -947,6 +948,7 @@ struct clk_fractional_divider {
u8 nwidth;
u32 nmask;
u8 flags;
+ unsigned long max_prate;
void (*approximation)(struct clk_hw *hw,
unsigned long rate, unsigned long *parent_rate,
unsigned long *m, unsigned long *n);
From 1d1bb3b1942d5f45e1f57f2656375f046039bfdb Mon Sep 17 00:00:00 2001
From: Elaine Zhang <zhangqing@rock-chips.com>
Date: Wed, 14 Oct 2020 10:28:09 +0800
Subject: [PATCH] clk: rockchip: fix up the frac clk get rate error
support fractional divider with one level and two level parent clock
.i.e:
normal fractional divider is:
|--\
---[GPLL]---| \ |--\
---[CPLL]---|mux|--[GATE]--[DIV]-----------------------| \
---[NPLL]---| / | |mux|--[GATE]--[UART0]
|--/ |--[GATE]--[FRACDIV]--| /
|--/
but rk3399 uart is special:
|--\
---[GPLL]---| \ |--\
---[CPLL]---|mux|--|--[GATE]--[DIV]-----------------------| \
---[NPLL]---| / | | |mux|--[GATE]--[UART1]
|--/ | |--[GATE]--[FRACDIV]--| /
| |--/
|
| |--\
|--[GATE]--[DIV]-----------------------| \
| | |mux|--[GATE]--[UART2]
| |--[GATE]--[FRACDIV]--| /
| |--/
|
| |--\
|--[GATE]--[DIV]-----------------------| \
| |mux|--[GATE]--[UART3]
|--[GATE]--[FRACDIV]--| /
|--/
The special fractional divider, there are two levels of clock between FRACDIV and PLL.
Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
---
drivers/clk/rockchip/clk.c | 19 ++++++++++++-------
1 file changed, 12 insertions(+), 7 deletions(-)
diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c
index 9d56a93e854c..d8ca75f90b25 100644
--- a/drivers/clk/rockchip/clk.c
+++ b/drivers/clk/rockchip/clk.c
@@ -188,16 +188,21 @@ static void rockchip_fractional_approximation(struct clk_hw *hw,
if (((rate * 20 > p_rate) && (p_rate % rate != 0)) ||
(fd->max_prate && fd->max_prate < p_rate)) {
p_parent = clk_hw_get_parent(clk_hw_get_parent(hw));
- p_parent_rate = clk_hw_get_rate(p_parent);
- *parent_rate = p_parent_rate;
- if (fd->max_prate && p_parent_rate > fd->max_prate) {
- div = DIV_ROUND_UP(p_parent_rate, fd->max_prate);
- *parent_rate = p_parent_rate / div;
+ if (!p_parent) {
+ *parent_rate = p_rate;
+ } else {
+ p_parent_rate = clk_hw_get_rate(p_parent);
+ *parent_rate = p_parent_rate;
+ if (fd->max_prate && p_parent_rate > fd->max_prate) {
+ div = DIV_ROUND_UP(p_parent_rate,
+ fd->max_prate);
+ *parent_rate = p_parent_rate / div;
+ }
}
if (*parent_rate < rate * 20) {
- pr_err("%s parent_rate(%ld) is low than rate(%ld)*20, fractional div is not allowed\n",
- clk_hw_get_name(hw), *parent_rate, rate);
+ pr_warn("%s p_rate(%ld) is low than rate(%ld)*20, use integer or half-div\n",
+ clk_hw_get_name(hw), *parent_rate, rate);
*m = 0;
*n = 1;
return;
From 4b0116e4c469fc0d2393b5c8e0f672fdd6e6a9b3 Mon Sep 17 00:00:00 2001
From: Elaine Zhang <zhangqing@rock-chips.com>
Date: Wed, 14 Oct 2020 10:28:10 +0800
Subject: [PATCH] clk: rockchip: add a clock-type for muxes based in the pmugrf
Rockchip socs often have some tiny number of muxes not controlled from
the core clock controller but through bits set in the pmugrf.
Use MUXPMUGRF() to cover this special clock-type.
Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
---
drivers/clk/rockchip/clk.c | 9 +++++++++
drivers/clk/rockchip/clk.h | 17 +++++++++++++++++
2 files changed, 26 insertions(+)
diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c
index d8ca75f90b25..66639a610172 100644
--- a/drivers/clk/rockchip/clk.c
+++ b/drivers/clk/rockchip/clk.c
@@ -407,6 +407,8 @@ struct rockchip_clk_provider *rockchip_clk_init(struct device_node *np,
ctx->grf = syscon_regmap_lookup_by_phandle(ctx->cru_node,
"rockchip,grf");
+ ctx->pmugrf = syscon_regmap_lookup_by_phandle(ctx->cru_node,
+ "rockchip,pmugrf");
return ctx;
@@ -485,6 +487,13 @@ void rockchip_clk_register_branches(struct rockchip_clk_provider *ctx,
list->mux_shift, list->mux_width,
list->mux_flags);
break;
+ case branch_muxpmugrf:
+ clk = rockchip_clk_register_muxgrf(list->name,
+ list->parent_names, list->num_parents,
+ flags, ctx->pmugrf, list->muxdiv_offset,
+ list->mux_shift, list->mux_width,
+ list->mux_flags);
+ break;
case branch_divider:
if (list->div_table)
clk = clk_register_divider_table(NULL,
diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h
index 0d401ce09a54..ae059b7744f9 100644
--- a/drivers/clk/rockchip/clk.h
+++ b/drivers/clk/rockchip/clk.h
@@ -238,6 +238,7 @@ struct rockchip_clk_provider {
struct clk_onecell_data clk_data;
struct device_node *cru_node;
struct regmap *grf;
+ struct regmap *pmugrf;
spinlock_t lock;
};
@@ -390,6 +391,7 @@ enum rockchip_clk_branch_type {
branch_composite,
branch_mux,
branch_muxgrf,
+ branch_muxpmugrf,
branch_divider,
branch_fraction_divider,
branch_gate,
@@ -662,6 +664,21 @@ struct rockchip_clk_branch {
.gate_offset = -1, \
}
+#define MUXPMUGRF(_id, cname, pnames, f, o, s, w, mf) \
+ { \
+ .id = _id, \
+ .branch_type = branch_muxpmugrf, \
+ .name = cname, \
+ .parent_names = pnames, \
+ .num_parents = ARRAY_SIZE(pnames), \
+ .flags = f, \
+ .muxdiv_offset = o, \
+ .mux_shift = s, \
+ .mux_width = w, \
+ .mux_flags = mf, \
+ .gate_offset = -1, \
+ }
+
#define DIV(_id, cname, pname, f, o, s, w, df) \
{ \
.id = _id, \
From a6daf8322c498e61804e02f2c02ad48187659de9 Mon Sep 17 00:00:00 2001
From: Elaine Zhang <zhangqing@rock-chips.com>
Date: Wed, 14 Oct 2020 10:28:11 +0800
Subject: [PATCH] clk: rockchip: add pll up and down when change pll freq
set pll sequence:
->set pll to slow mode or other plls
->set pll down
->set pll params
->set pll up
->wait pll lock status
->set pll to normal mode
To slove the system error:
wait_pll_lock: timeout waiting for pll to lock
pll_set_params: pll update unsucessful,
trying to restore old params
Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
---
drivers/clk/rockchip/clk-pll.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c
index 4c6c9167ef50..8adc6f54a605 100644
--- a/drivers/clk/rockchip/clk-pll.c
+++ b/drivers/clk/rockchip/clk-pll.c
@@ -210,6 +210,11 @@ static int rockchip_rk3036_pll_set_params(struct rockchip_clk_pll *pll,
rate_change_remuxed = 1;
}
+ /* set pll power down */
+ writel(HIWORD_UPDATE(RK3036_PLLCON1_PWRDOWN,
+ RK3036_PLLCON1_PWRDOWN, 0),
+ pll->reg_base + RK3036_PLLCON(1));
+
/* update pll values */
writel_relaxed(HIWORD_UPDATE(rate->fbdiv, RK3036_PLLCON0_FBDIV_MASK,
RK3036_PLLCON0_FBDIV_SHIFT) |
@@ -231,6 +236,11 @@ static int rockchip_rk3036_pll_set_params(struct rockchip_clk_pll *pll,
pllcon |= rate->frac << RK3036_PLLCON2_FRAC_SHIFT;
writel_relaxed(pllcon, pll->reg_base + RK3036_PLLCON(2));
+ /* set pll power up */
+ writel(HIWORD_UPDATE(0, RK3036_PLLCON1_PWRDOWN, 0),
+ pll->reg_base + RK3036_PLLCON(1));
+ udelay(1);
+
/* wait for the pll to lock */
ret = rockchip_rk3036_pll_wait_lock(pll);
if (ret) {
@@ -692,6 +702,11 @@ static int rockchip_rk3399_pll_set_params(struct rockchip_clk_pll *pll,
rate_change_remuxed = 1;
}
+ /* set pll power down */
+ writel(HIWORD_UPDATE(RK3399_PLLCON3_PWRDOWN,
+ RK3399_PLLCON3_PWRDOWN, 0),
+ pll->reg_base + RK3399_PLLCON(3));
+
/* update pll values */
writel_relaxed(HIWORD_UPDATE(rate->fbdiv, RK3399_PLLCON0_FBDIV_MASK,
RK3399_PLLCON0_FBDIV_SHIFT),
@@ -715,6 +730,12 @@ static int rockchip_rk3399_pll_set_params(struct rockchip_clk_pll *pll,
RK3399_PLLCON3_DSMPD_SHIFT),
pll->reg_base + RK3399_PLLCON(3));
+ /* set pll power up */
+ writel(HIWORD_UPDATE(0,
+ RK3399_PLLCON3_PWRDOWN, 0),
+ pll->reg_base + RK3399_PLLCON(3));
+ udelay(1);
+
/* wait for the pll to lock */
ret = rockchip_rk3399_pll_wait_lock(pll);
if (ret) {
From 381edaef837e98a052a60374d6bbbf914cf3bdb2 Mon Sep 17 00:00:00 2001
From: Elaine Zhang <zhangqing@rock-chips.com>
Date: Wed, 14 Oct 2020 10:28:53 +0800
Subject: [PATCH] clk: rockchip: support pll setting by auto
If setting freq is not support in rockchip_pll_rate_table,
It can calculate and set pll params by auto.
Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
---
drivers/clk/rockchip/clk-pll.c | 215 ++++++++++++++++++++++++++++++---
1 file changed, 200 insertions(+), 15 deletions(-)
diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c
index 8adc6f54a605..e8ca86f5b7d1 100644
--- a/drivers/clk/rockchip/clk-pll.c
+++ b/drivers/clk/rockchip/clk-pll.c
@@ -15,6 +15,7 @@
#include <linux/iopoll.h>
#include <linux/regmap.h>
#include <linux/clk.h>
+#include <linux/gcd.h>
#include "clk.h"
#define PLL_MODE_MASK 0x3
@@ -47,6 +48,198 @@ struct rockchip_clk_pll {
#define to_rockchip_clk_pll_nb(nb) \
container_of(nb, struct rockchip_clk_pll, clk_nb)
+#define MHZ (1000UL * 1000UL)
+#define KHZ (1000UL)
+
+/* CLK_PLL_TYPE_RK3066_AUTO type ops */
+#define PLL_FREF_MIN (269 * KHZ)
+#define PLL_FREF_MAX (2200 * MHZ)
+
+#define PLL_FVCO_MIN (440 * MHZ)
+#define PLL_FVCO_MAX (2200 * MHZ)
+
+#define PLL_FOUT_MIN (27500 * KHZ)
+#define PLL_FOUT_MAX (2200 * MHZ)
+
+#define PLL_NF_MAX (4096)
+#define PLL_NR_MAX (64)
+#define PLL_NO_MAX (16)
+
+/* CLK_PLL_TYPE_RK3036/3366/3399_AUTO type ops */
+#define MIN_FOUTVCO_FREQ (800 * MHZ)
+#define MAX_FOUTVCO_FREQ (2000 * MHZ)
+
+static struct rockchip_pll_rate_table auto_table;
+
+static struct rockchip_pll_rate_table *rk_pll_rate_table_get(void)
+{
+ return &auto_table;
+}
+
+static int rockchip_pll_clk_set_postdiv(unsigned long fout_hz,
+ u32 *postdiv1,
+ u32 *postdiv2,
+ u32 *foutvco)
+{
+ unsigned long freq;
+
+ if (fout_hz < MIN_FOUTVCO_FREQ) {
+ for (*postdiv1 = 1; *postdiv1 <= 7; (*postdiv1)++) {
+ for (*postdiv2 = 1; *postdiv2 <= 7; (*postdiv2)++) {
+ freq = fout_hz * (*postdiv1) * (*postdiv2);
+ if (freq >= MIN_FOUTVCO_FREQ &&
+ freq <= MAX_FOUTVCO_FREQ) {
+ *foutvco = freq;
+ return 0;
+ }
+ }
+ }
+ pr_err("CANNOT FIND postdiv1/2 to make fout in range from 800M to 2000M,fout = %lu\n",
+ fout_hz);
+ } else {
+ *postdiv1 = 1;
+ *postdiv2 = 1;
+ }
+ return 0;
+}
+
+static struct rockchip_pll_rate_table *
+rockchip_pll_clk_set_by_auto(struct rockchip_clk_pll *pll,
+ unsigned long fin_hz,
+ unsigned long fout_hz)
+{
+ struct rockchip_pll_rate_table *rate_table = rk_pll_rate_table_get();
+ /* FIXME set postdiv1/2 always 1*/
+ u32 foutvco = fout_hz;
+ u64 fin_64, frac_64;
+ u32 f_frac, postdiv1, postdiv2;
+ unsigned long clk_gcd = 0;
+
+ if (fin_hz == 0 || fout_hz == 0 || fout_hz == fin_hz)
+ return NULL;
+
+ rockchip_pll_clk_set_postdiv(fout_hz, &postdiv1, &postdiv2, &foutvco);
+ rate_table->postdiv1 = postdiv1;
+ rate_table->postdiv2 = postdiv2;
+ rate_table->dsmpd = 1;
+
+ if (fin_hz / MHZ * MHZ == fin_hz && fout_hz / MHZ * MHZ == fout_hz) {
+ fin_hz /= MHZ;
+ foutvco /= MHZ;
+ clk_gcd = gcd(fin_hz, foutvco);
+ rate_table->refdiv = fin_hz / clk_gcd;
+ rate_table->fbdiv = foutvco / clk_gcd;
+
+ rate_table->frac = 0;
+
+ pr_debug("fin = %lu, fout = %lu, clk_gcd = %lu, refdiv = %u, fbdiv = %u, postdiv1 = %u, postdiv2 = %u, frac = %u\n",
+ fin_hz, fout_hz, clk_gcd, rate_table->refdiv,
+ rate_table->fbdiv, rate_table->postdiv1,
+ rate_table->postdiv2, rate_table->frac);
+ } else {
+ pr_debug("frac div running, fin_hz = %lu, fout_hz = %lu, fin_INT_mhz = %lu, fout_INT_mhz = %lu\n",
+ fin_hz, fout_hz,
+ fin_hz / MHZ * MHZ,
+ fout_hz / MHZ * MHZ);
+ pr_debug("frac get postdiv1 = %u, postdiv2 = %u, foutvco = %u\n",
+ rate_table->postdiv1, rate_table->postdiv2, foutvco);
+ clk_gcd = gcd(fin_hz / MHZ, foutvco / MHZ);
+ rate_table->refdiv = fin_hz / MHZ / clk_gcd;
+ rate_table->fbdiv = foutvco / MHZ / clk_gcd;
+ pr_debug("frac get refdiv = %u, fbdiv = %u\n",
+ rate_table->refdiv, rate_table->fbdiv);
+
+ rate_table->frac = 0;
+
+ f_frac = (foutvco % MHZ);
+ fin_64 = fin_hz;
+ do_div(fin_64, (u64)rate_table->refdiv);
+ frac_64 = (u64)f_frac << 24;
+ do_div(frac_64, fin_64);
+ rate_table->frac = (u32)frac_64;
+ if (rate_table->frac > 0)
+ rate_table->dsmpd = 0;
+ pr_debug("frac = %x\n", rate_table->frac);
+ }
+ return rate_table;
+}
+
+static struct rockchip_pll_rate_table *
+rockchip_rk3066_pll_clk_set_by_auto(struct rockchip_clk_pll *pll,
+ unsigned long fin_hz,
+ unsigned long fout_hz)
+{
+ struct rockchip_pll_rate_table *rate_table = rk_pll_rate_table_get();
+ u32 nr, nf, no, nonr;
+ u32 nr_out, nf_out, no_out;
+ u32 n;
+ u32 numerator, denominator;
+ u64 fref, fvco, fout;
+ unsigned long clk_gcd = 0;
+
+ nr_out = PLL_NR_MAX + 1;
+ no_out = 0;
+ nf_out = 0;
+
+ if (fin_hz == 0 || fout_hz == 0 || fout_hz == fin_hz)
+ return NULL;
+
+ clk_gcd = gcd(fin_hz, fout_hz);
+
+ numerator = fout_hz / clk_gcd;
+ denominator = fin_hz / clk_gcd;
+
+ for (n = 1;; n++) {
+ nf = numerator * n;
+ nonr = denominator * n;
+ if (nf > PLL_NF_MAX || nonr > (PLL_NO_MAX * PLL_NR_MAX))
+ break;
+
+ for (no = 1; no <= PLL_NO_MAX; no++) {
+ if (!(no == 1 || !(no % 2)))
+ continue;
+
+ if (nonr % no)
+ continue;
+ nr = nonr / no;
+
+ if (nr > PLL_NR_MAX)
+ continue;
+
+ fref = fin_hz / nr;
+ if (fref < PLL_FREF_MIN || fref > PLL_FREF_MAX)
+ continue;
+
+ fvco = fref * nf;
+ if (fvco < PLL_FVCO_MIN || fvco > PLL_FVCO_MAX)
+ continue;
+
+ fout = fvco / no;
+ if (fout < PLL_FOUT_MIN || fout > PLL_FOUT_MAX)
+ continue;
+
+ /* select the best from all available PLL settings */
+ if ((no > no_out) ||
+ ((no == no_out) && (nr < nr_out))) {
+ nr_out = nr;
+ nf_out = nf;
+ no_out = no;
+ }
+ }
+ }
+
+ /* output the best PLL setting */
+ if ((nr_out <= PLL_NR_MAX) && (no_out > 0)) {
+ rate_table->nr = nr_out;
+ rate_table->nf = nf_out;
+ rate_table->no = no_out;
+ } else {
+ return NULL;
+ }
+
+ return rate_table;
+}
+
static const struct rockchip_pll_rate_table *rockchip_get_pll_settings(
struct rockchip_clk_pll *pll, unsigned long rate)
{
@@ -58,24 +251,16 @@ static const struct rockchip_pll_rate_table *rockchip_get_pll_settings(
return &rate_table[i];
}
- return NULL;
+ if (pll->type == pll_rk3066)
+ return rockchip_rk3066_pll_clk_set_by_auto(pll, 24 * MHZ, rate);
+ else
+ return rockchip_pll_clk_set_by_auto(pll, 24 * MHZ, rate);
}
static long rockchip_pll_round_rate(struct clk_hw *hw,
unsigned long drate, unsigned long *prate)
{
- struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
- const struct rockchip_pll_rate_table *rate_table = pll->rate_table;
- int i;
-
- /* Assumming rate_table is in descending order */
- for (i = 0; i < pll->rate_count; i++) {
- if (drate >= rate_table[i].rate)
- return rate_table[i].rate;
- }
-
- /* return minimum supported value */
- return rate_table[i - 1].rate;
+ return drate;
}
/*
@@ -165,7 +350,7 @@ static unsigned long rockchip_rk3036_pll_recalc_rate(struct clk_hw *hw,
{
struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
struct rockchip_pll_rate_table cur;
- u64 rate64 = prate;
+ u64 rate64 = prate, frac_rate64 = prate;
rockchip_rk3036_pll_get_params(pll, &cur);
@@ -174,7 +359,7 @@ static unsigned long rockchip_rk3036_pll_recalc_rate(struct clk_hw *hw,
if (cur.dsmpd == 0) {
/* fractional mode */
- u64 frac_rate64 = prate * cur.frac;
+ frac_rate64 *= cur.frac;
do_div(frac_rate64, cur.refdiv);
rate64 += frac_rate64 >> 24;