1508 lines
46 KiB
Diff
1508 lines
46 KiB
Diff
From 6adabb3a26a433cc80d906eb42908c558a119665 Mon Sep 17 00:00:00 2001
|
|
From: Alexander Horner <33007665+alexhorner@users.noreply.github.com>
|
|
Date: Tue, 14 Feb 2023 22:44:18 +0000
|
|
Subject: [PATCH 28/31] Add GPIO/PINCTRL and HWRNG/Crypto drivers
|
|
|
|
---
|
|
drivers/crypto/Kconfig | 11 +
|
|
drivers/crypto/Makefile | 1 +
|
|
drivers/crypto/bflb-seceng.c | 670 +++++++++++++++++++++++
|
|
drivers/pinctrl/Kconfig | 16 +
|
|
drivers/pinctrl/Makefile | 1 +
|
|
drivers/pinctrl/pinctrl-bflb.c | 719 +++++++++++++++++++++++++
|
|
include/dt-bindings/mailbox/bflb-ipc.h | 3 +-
|
|
7 files changed, 1420 insertions(+), 1 deletion(-)
|
|
create mode 100644 drivers/crypto/bflb-seceng.c
|
|
create mode 100644 drivers/pinctrl/pinctrl-bflb.c
|
|
|
|
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
|
|
index dfb103f81a64..e8de3d60ffd8 100644
|
|
--- a/drivers/crypto/Kconfig
|
|
+++ b/drivers/crypto/Kconfig
|
|
@@ -13,6 +13,17 @@ if CRYPTO_HW
|
|
|
|
source "drivers/crypto/allwinner/Kconfig"
|
|
|
|
+config CRYPTO_DEV_BFLB_SECENG
|
|
+ tristate "Bouffalo Lab Secure Engine Driver"
|
|
+ depends on SOC_BOUFFALOLAB
|
|
+ select CRYPTO_RNG
|
|
+ help
|
|
+ This driver provides support for the Random Number
|
|
+ Generator hardware found on Bouffalo Lab BL808 SoCs.
|
|
+
|
|
+ To compile this driver as a module, choose M here. The
|
|
+ module will be called bflb-seceng. If unsure, say N.
|
|
+
|
|
config CRYPTO_DEV_PADLOCK
|
|
tristate "Support for VIA PadLock ACE"
|
|
depends on X86 && !UML
|
|
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
|
|
index fa8bf1be1a8c..1b5c60587c43 100644
|
|
--- a/drivers/crypto/Makefile
|
|
+++ b/drivers/crypto/Makefile
|
|
@@ -8,6 +8,7 @@ obj-$(CONFIG_CRYPTO_DEV_ATMEL_TDES) += atmel-tdes.o
|
|
obj-$(CONFIG_CRYPTO_DEV_ATMEL_I2C) += atmel-i2c.o
|
|
obj-$(CONFIG_CRYPTO_DEV_ATMEL_ECC) += atmel-ecc.o
|
|
obj-$(CONFIG_CRYPTO_DEV_ATMEL_SHA204A) += atmel-sha204a.o
|
|
+obj-$(CONFIG_CRYPTO_DEV_BFLB_SECENG) += bflb-seceng.o
|
|
obj-$(CONFIG_CRYPTO_DEV_CAVIUM_ZIP) += cavium/
|
|
obj-$(CONFIG_CRYPTO_DEV_CCP) += ccp/
|
|
obj-$(CONFIG_CRYPTO_DEV_CCREE) += ccree/
|
|
diff --git a/drivers/crypto/bflb-seceng.c b/drivers/crypto/bflb-seceng.c
|
|
new file mode 100644
|
|
index 000000000000..3e450f06ddea
|
|
--- /dev/null
|
|
+++ b/drivers/crypto/bflb-seceng.c
|
|
@@ -0,0 +1,670 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+//
|
|
+// Bouffalo Lab SoC Secure Engine driver
|
|
+//
|
|
+// Based on qcom-rng.c
|
|
+// Copyright (c) 2017-18 Linaro Limited
|
|
+
|
|
+#include <linux/bitfield.h>
|
|
+#include <linux/bits.h>
|
|
+#include <crypto/internal/rng.h>
|
|
+#include <linux/crypto.h>
|
|
+#include <linux/hw_random.h>
|
|
+#include <linux/of.h>
|
|
+#include <linux/regmap.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/sched.h>
|
|
+
|
|
+//Register map
|
|
+//se_sha_0_ctrl
|
|
+#define REG_SECENG_SHA_0_CTRL 0 //Offset from base address
|
|
+#define REG_SECENG_SHA_0_CTRL_MSG_LEN GENMASK(31, 16)
|
|
+#define REG_SECENG_SHA_0_CTRL_LINK_MODE BIT(15)
|
|
+#define REG_SECENG_SHA_0_CTRL_MODE_EXT GENMASK(13, 12)
|
|
+#define REG_SECENG_SHA_0_CTRL_INT_MASK BIT(11)
|
|
+#define REG_SECENG_SHA_0_CTRL_INT_SET_1T BIT(10)
|
|
+#define REG_SECENG_SHA_0_CTRL_INT_CLR_1T BIT(9)
|
|
+#define REG_SECENG_SHA_0_CTRL_INT BIT(8)
|
|
+#define REG_SECENG_SHA_0_CTRL_HASH_SEL BIT(6)
|
|
+#define REG_SECENG_SHA_0_CTRL_EN BIT(5)
|
|
+#define REG_SECENG_SHA_0_CTRL_MODE GENMASK(4, 2)
|
|
+#define REG_SECENG_SHA_0_CTRL_INT_TRIG_1T BIT(1)
|
|
+#define REG_SECENG_SHA_0_CTRL_BUSY BIT(0)
|
|
+
|
|
+//se_sha_0_msa
|
|
+#define REG_SECENG_SHA_0_MSA 4
|
|
+
|
|
+//se_sha_0_status
|
|
+#define REG_SECENG_SHA_0_STATUS 8
|
|
+
|
|
+//se_sha_0_endian
|
|
+#define REG_SECENG_SHA_0_ENDIAN 12
|
|
+#define REG_SECENG_SHA_0_ENDIAN_VAL BIT(0)
|
|
+
|
|
+//se_sha_0_hash_l_0
|
|
+#define REG_SECENG_SHA_0_HASH_L_0 16
|
|
+
|
|
+//se_sha_0_hash_l_1
|
|
+#define REG_SECENG_SHA_0_HASH_L_1 20
|
|
+
|
|
+//se_sha_0_hash_l_2
|
|
+#define REG_SECENG_SHA_0_HASH_L_2 24
|
|
+
|
|
+//se_sha_0_hash_l_3
|
|
+#define REG_SECENG_SHA_0_HASH_L_3 28
|
|
+
|
|
+//se_sha_0_hash_l_4
|
|
+#define REG_SECENG_SHA_0_HASH_L_4 32
|
|
+
|
|
+//se_sha_0_hash_l_5
|
|
+#define REG_SECENG_SHA_0_HASH_L_5 36
|
|
+
|
|
+//se_sha_0_hash_l_6
|
|
+#define REG_SECENG_SHA_0_HASH_L_6 40
|
|
+
|
|
+//se_sha_0_hash_l_7
|
|
+#define REG_SECENG_SHA_0_HASH_L_7 44
|
|
+
|
|
+//se_sha_0_hash_h_0
|
|
+#define REG_SECENG_SHA_0_HASH_H_0 48
|
|
+
|
|
+//se_sha_0_hash_h_1
|
|
+#define REG_SECENG_SHA_0_HASH_H_1 52
|
|
+
|
|
+//se_sha_0_hash_h_2
|
|
+#define REG_SECENG_SHA_0_HASH_H_2 56
|
|
+
|
|
+//se_sha_0_hash_h_3
|
|
+#define REG_SECENG_SHA_0_HASH_H_3 60
|
|
+
|
|
+//se_sha_0_hash_h_4
|
|
+#define REG_SECENG_SHA_0_HASH_H_4 64
|
|
+
|
|
+//se_sha_0_hash_h_5
|
|
+#define REG_SECENG_SHA_0_HASH_H_5 68
|
|
+
|
|
+//se_sha_0_hash_h_6
|
|
+#define REG_SECENG_SHA_0_HASH_H_6 72
|
|
+
|
|
+//se_sha_0_hash_h_7
|
|
+#define REG_SECENG_SHA_0_HASH_H_7 76
|
|
+
|
|
+//se_sha_0_link
|
|
+#define REG_SECENG_SHA_0_LINK 80
|
|
+
|
|
+//se_sha_0_ctrl_prot
|
|
+#define REG_SECENG_SHA_0_CTRL_PROT 252
|
|
+#define REG_SECENG_SHA_0_CTRL_PROT_ID1_EN BIT(2)
|
|
+#define REG_SECENG_SHA_0_CTRL_PROT_ID0_EN BIT(1)
|
|
+
|
|
+//se_aes_0_ctrl
|
|
+#define REG_SECENG_AES_0_CTRL 256
|
|
+#define REG_SECENG_AES_0_CTRL_MSG_LEN GENMASK(31, 16)
|
|
+#define REG_SECENG_AES_0_CTRL_LINK_MODE BIT(15)
|
|
+#define REG_SECENG_AES_0_CTRL_IV_SEL BIT(14)
|
|
+#define REG_SECENG_AES_0_CTRL_BLOCK_MODE GENMASK(13, 12)
|
|
+#define REG_SECENG_AES_0_CTRL_INT_MASK BIT(11)
|
|
+#define REG_SECENG_AES_0_CTRL_INT_SET_1T BIT(10)
|
|
+#define REG_SECENG_AES_0_CTRL_INT_CLR_1T BIT(9)
|
|
+#define REG_SECENG_AES_0_CTRL_INT BIT(8)
|
|
+#define REG_SECENG_AES_0_CTRL_HW_KEY_EN BIT(7)
|
|
+#define REG_SECENG_AES_0_CTRL_DEC_KEY_SEL BIT(6)
|
|
+#define REG_SECENG_AES_0_CTRL_DEC_EN BIT(5)
|
|
+#define REG_SECENG_AES_0_CTRL_MODE GENMASK(4, 3)
|
|
+#define REG_SECENG_AES_0_CTRL_EN BIT(2)
|
|
+#define REG_SECENG_AES_0_CTRL_TRIG_1T BIT(1)
|
|
+#define REG_SECENG_AES_0_CTRL_BUSY BIT(0)
|
|
+
|
|
+//se_aes_0_msa
|
|
+#define REG_SECENG_AES_0_MSA 260
|
|
+
|
|
+//se_aes_0_mda
|
|
+#define REG_SECENG_AES_0_MDA 264
|
|
+
|
|
+//se_aes_0_status
|
|
+#define REG_SECENG_AES_0_STATUS 268
|
|
+
|
|
+//se_aes_0_iv_0
|
|
+#define REG_SECENG_AES_0_IV_0 272
|
|
+
|
|
+//se_aes_0_iv_1
|
|
+#define REG_SECENG_AES_0_IV_1 276
|
|
+
|
|
+//se_aes_0_iv_2
|
|
+#define REG_SECENG_AES_0_IV_2 280
|
|
+
|
|
+//se_aes_0_iv_3
|
|
+#define REG_SECENG_AES_0_IV_3 284
|
|
+
|
|
+//se_aes_0_key_0
|
|
+#define REG_SECENG_AES_0_KEY_0 288
|
|
+
|
|
+//se_aes_0_key_1
|
|
+#define REG_SECENG_AES_0_KEY_1 292
|
|
+
|
|
+//se_aes_0_key_2
|
|
+#define REG_SECENG_AES_0_KEY_2 296
|
|
+
|
|
+//se_aes_0_key_3
|
|
+#define REG_SECENG_AES_0_KEY_3 300
|
|
+
|
|
+//se_aes_0_key_4
|
|
+#define REG_SECENG_AES_0_KEY_4 304
|
|
+
|
|
+//se_aes_0_key_5
|
|
+#define REG_SECENG_AES_0_KEY_5 308
|
|
+
|
|
+//se_aes_0_key_6
|
|
+#define REG_SECENG_AES_0_KEY_6 312
|
|
+
|
|
+//se_aes_0_key_7
|
|
+#define REG_SECENG_AES_0_KEY_7 316
|
|
+
|
|
+//se_aes_0_key_sel
|
|
+#define REG_SECENG_AES_0_KEY_SEL 320
|
|
+#define REG_SECENG_AES_0_KEY_SEL_VAL GENMASK(1, 0)
|
|
+
|
|
+//se_aes_1_key_sel
|
|
+#define REG_SECENG_AES_1_KEY_SEL 324
|
|
+#define REG_SECENG_AES_01KEY_SEL_VAL GENMASK(1, 0)
|
|
+
|
|
+//se_aes_0_endian
|
|
+#define REG_SECENG_AES_0_ENDIAN 328
|
|
+#define REG_SECENG_AES_0_ENDIAN_CTR_LEN GENMASK(31, 30)
|
|
+#define REG_SECENG_AES_0_ENDIAN_TWK BIT(4)
|
|
+#define REG_SECENG_AES_0_ENDIAN_IV BIT(3)
|
|
+#define REG_SECENG_AES_0_ENDIAN_KEY BIT(2)
|
|
+#define REG_SECENG_AES_0_ENDIAN_DIN BIT(1)
|
|
+#define REG_SECENG_AES_0_ENDIAN_DOUT BIT(0)
|
|
+
|
|
+//se_aes_sboot
|
|
+#define REG_SECENG_AES_SBOOT 332
|
|
+#define REG_SECENG_AES_SBOOT_UNI_LEN GENMASK(31, 16)
|
|
+#define REG_SECENG_AES_SBOOT_XTS_MODE BIT(15)
|
|
+#define REG_SECENG_AES_SBOOT_KEY_SEL BIT(0)
|
|
+
|
|
+//se_aes_0_link
|
|
+#define REG_SECENG_AES_0_LINK 336
|
|
+
|
|
+//se_aes_0_ctrl_prot
|
|
+#define REG_SECENG_AES_0_CTRL_PROT 508
|
|
+#define REG_SECENG_AES_0_CTRL_PROT_ID1_EN BIT(2)
|
|
+#define REG_SECENG_AES_0_CTRL_PROT_ID0_EN BIT(1)
|
|
+
|
|
+//se_trng_0_ctrl_0
|
|
+#define REG_SECENG_TRNG_0_CTRL_0 512
|
|
+#define REG_SECENG_TRNG_0_CTRL_0_MANUAL_EN BIT(15)
|
|
+#define REG_SECENG_TRNG_0_CTRL_0_MANUAL_RESEED BIT(14)
|
|
+#define REG_SECENG_TRNG_0_CTRL_0_MANUAL_FUN_SEL BIT(13)
|
|
+#define REG_SECENG_TRNG_0_CTRL_0_INT_MASK BIT(11)
|
|
+#define REG_SECENG_TRNG_0_CTRL_0_INT_SET_1T BIT(10)
|
|
+#define REG_SECENG_TRNG_0_CTRL_0_INT_CLR_1T BIT(9)
|
|
+#define REG_SECENG_TRNG_0_CTRL_0_INT BIT(8)
|
|
+#define REG_SECENG_TRNG_0_CTRL_0_HT_ERROR BIT(4)
|
|
+#define REG_SECENG_TRNG_0_CTRL_0_DOUT_CLR_1T BIT(3)
|
|
+#define REG_SECENG_TRNG_0_CTRL_0_EN BIT(2)
|
|
+#define REG_SECENG_TRNG_0_CTRL_0_TRIG_1T BIT(1)
|
|
+#define REG_SECENG_TRNG_0_CTRL_0_BUSY BIT(0)
|
|
+
|
|
+//se_trng_0_status
|
|
+#define REG_SECENG_TRNG_0_STATUS 516
|
|
+
|
|
+//se_trng_0_dout_0
|
|
+#define REG_SECENG_TRNG_0_DOUT_0 520
|
|
+
|
|
+//se_trng_0_dout_1
|
|
+#define REG_SECENG_TRNG_0_DOUT_1 524
|
|
+
|
|
+//se_trng_0_dout_2
|
|
+#define REG_SECENG_TRNG_0_DOUT_2 528
|
|
+
|
|
+//se_trng_0_dout_3
|
|
+#define REG_SECENG_TRNG_0_DOUT_3 532
|
|
+
|
|
+//se_trng_0_dout_4
|
|
+#define REG_SECENG_TRNG_0_DOUT_4 536
|
|
+
|
|
+//se_trng_0_dout_5
|
|
+#define REG_SECENG_TRNG_0_DOUT_5 540
|
|
+
|
|
+//se_trng_0_dout_6
|
|
+#define REG_SECENG_TRNG_0_DOUT_6 544
|
|
+
|
|
+//se_trng_0_dout_7
|
|
+#define REG_SECENG_TRNG_0_DOUT_7 548
|
|
+
|
|
+//se_trng_0_test
|
|
+#define REG_SECENG_TRNG_0_TEST 552
|
|
+#define REG_SECENG_TRNG_0_TEST_HT_ALARM_N GENMASK(11, 4)
|
|
+#define REG_SECENG_TRNG_0_TEST_HT_DIS BIT(3)
|
|
+#define REG_SECENG_TRNG_0_TEST_CP_BYPASS BIT(2)
|
|
+#define REG_SECENG_TRNG_0_TEST_CP_TEST_EN BIT(1)
|
|
+#define REG_SECENG_TRNG_0_TEST_TEST_EN BIT(0)
|
|
+
|
|
+//se_trng_0_ctrl_1
|
|
+#define REG_SECENG_TRNG_0_CTRL_1_RESEED_N_LSB 556
|
|
+
|
|
+//se_trng_0_ctrl_2
|
|
+#define REG_SECENG_TRNG_0_CTRL_2_RESEED_N_MSB 560
|
|
+#define REG_SECENG_TRNG_0_CTRL_1_RESEED_N_MSB_VALUE GENMASK(15, 0)
|
|
+
|
|
+//se_trng_0_ctrl_3
|
|
+#define REG_SECENG_TRNG_0_CTRL_3 564
|
|
+#define REG_SECENG_TRNG_0_CTRL_3_ROSC_EN BIT(31)
|
|
+#define REG_SECENG_TRNG_0_CTRL_3_HT_OD_EN BIT(26)
|
|
+#define REG_SECENG_TRNG_0_CTRL_3_HT_APT_C GENMASK(25, 16)
|
|
+#define REG_SECENG_TRNG_0_CTRL_3_HT_RCT_C GENMASK(15, 8)
|
|
+#define REG_SECENG_TRNG_0_CTRL_3_CP_RATIO GENMASK(7, 0)
|
|
+
|
|
+//se_trng_0_test_out_0
|
|
+#define REG_SECENG_TRNG_0_TEST_OUT_0 576
|
|
+
|
|
+//se_trng_0_test_out_1
|
|
+#define REG_SECENG_TRNG_0_TEST_OUT_1 580
|
|
+
|
|
+//se_trng_0_test_out_2
|
|
+#define REG_SECENG_TRNG_0_TEST_OUT_2 584
|
|
+
|
|
+//se_trng_0_test_out_3
|
|
+#define REG_SECENG_TRNG_0_TEST_OUT_3 588
|
|
+
|
|
+//se_trng_0_ctrl_prot
|
|
+#define REG_SECENG_TRNG_0_CTRL_PROT 764
|
|
+#define REG_SECENG_TRNG_0_CTRL_PROT_ID1_EN BIT(2)
|
|
+#define REG_SECENG_TRNG_0_CTRL_PROT_ID0_EN BIT(1)
|
|
+
|
|
+//se_pka_0_ctrl_0
|
|
+#define REG_SECENG_PKA_0_CTRL_0 768
|
|
+#define REG_SECENG_PKA_0_CTRL_0_STATUS GENMASK(31, 16)
|
|
+#define REG_SECENG_PKA_0_CTRL_0_STATUS_CLR_1T BIT(15)
|
|
+#define REG_SECENG_PKA_0_CTRL_0_RAM_CLR_MD BIT(13)
|
|
+#define REG_SECENG_PKA_0_CTRL_0_ENDIAN BIT(12)
|
|
+#define REG_SECENG_PKA_0_CTRL_0_INT_MASK BIT(11)
|
|
+#define REG_SECENG_PKA_0_CTRL_0_INT_SET BIT(10)
|
|
+#define REG_SECENG_PKA_0_CTRL_0_INT_CLR_1T BIT(9)
|
|
+#define REG_SECENG_PKA_0_CTRL_0_INT BIT(8)
|
|
+#define REG_SECENG_PKA_0_CTRL_0_PROT_MD GENMASK(7, 4)
|
|
+#define REG_SECENG_PKA_0_CTRL_0_EN BIT(3)
|
|
+#define REG_SECENG_PKA_0_CTRL_0_BUSY BIT(2)
|
|
+#define REG_SECENG_PKA_0_CTRL_0_DONE_CLR_1T BIT(1)
|
|
+#define REG_SECENG_PKA_0_CTRL_0_DONE BIT(0)
|
|
+
|
|
+//se_pka_0_seed
|
|
+#define REG_SECENG_PKA_0_SEED 780
|
|
+
|
|
+//se_pka_0_ctrl_1
|
|
+#define REG_SECENG_PKA_0_CTRL_1 784
|
|
+#define REG_SECENG_PKA_0_CTRL_1_HBYPASS BIT(3)
|
|
+#define REG_SECENG_PKA_0_CTRL_1_HBURST GENMASK(2, 0)
|
|
+
|
|
+//se_pka_0_rw
|
|
+#define REG_SECENG_PKA_0_RW 832
|
|
+//This is a confusing register which I have not mapped because
|
|
+//"BL808 Reference Manual 1.2 EN" seems wrong
|
|
+
|
|
+//se_pka_0_rw_burst
|
|
+#define REG_SECENG_PKA_0_RW_BURST 864
|
|
+//This is a confusing register which I have not mapped because
|
|
+//"BL808 Reference Manual 1.2 EN" seems wrong
|
|
+
|
|
+//se_pka_0_ctrl_prot
|
|
+#define REG_SECENG_PKA_0_CTRL_PROT 1020
|
|
+#define REG_SECENG_PKA_0_CTRL_PROT_ID1_EN BIT(2)
|
|
+#define REG_SECENG_PKA_0_CTRL_PROT_ID0_EN BIT(1)
|
|
+
|
|
+//se_cdet_0_ctrl_0
|
|
+#define REG_SECENG_CDET_0_CTRL_0 1024
|
|
+#define REG_SECENG_CDET_0_CTRL_0_G_LOOP_MIN GENMASK(31, 24)
|
|
+#define REG_SECENG_CDET_0_CTRL_0_G_LOOP_MAX GENMASK(23, 16)
|
|
+#define REG_SECENG_CDET_0_CTRL_0_STATUS GENMASK(15, 2)
|
|
+#define REG_SECENG_CDET_0_CTRL_0_ERROR BIT(1)
|
|
+#define REG_SECENG_CDET_0_CTRL_0_EN BIT(0)
|
|
+
|
|
+//se_cdet_0_ctrl_1
|
|
+#define REG_SECENG_CDET_0_CTRL_1 1028
|
|
+#define REG_SECENG_CDET_0_CTRL_1_G_SLP_N GENMASK(23, 16)
|
|
+#define REG_SECENG_CDET_0_CTRL_1_T_DLY_N GENMASK(15, 8)
|
|
+#define REG_SECENG_CDET_0_CTRL_1_T_LOOP_N GENMASK(7, 0)
|
|
+
|
|
+//se_cdet_0_ctrl_prot
|
|
+#define REG_SECENG_CDET_0_CTRL_PROT 1276
|
|
+#define REG_SECENG_CDET_0_CTRL_PROT_ID1_EN BIT(2)
|
|
+#define REG_SECENG_CDET_0_CTRL_PROT_ID0_EN BIT(1)
|
|
+#define REG_SECENG_CDET_0_CTRL_PROT_PROT_EN BIT(0)
|
|
+
|
|
+//se_gmac_0_ctrl_0
|
|
+#define REG_SECENG_GMAC_0_CTRL_0 1280
|
|
+#define REG_SECENG_GMAC_0_CTRL_0_X_ENDIAN BIT(14)
|
|
+#define REG_SECENG_GMAC_0_CTRL_0_H_ENDIAN BIT(13)
|
|
+#define REG_SECENG_GMAC_0_CTRL_0_T_ENDIAN BIT(12)
|
|
+#define REG_SECENG_GMAC_0_CTRL_0_INT_MASK BIT(11)
|
|
+#define REG_SECENG_GMAC_0_CTRL_0_INT_SET_1T BIT(10)
|
|
+#define REG_SECENG_GMAC_0_CTRL_0_INT_CLR_1T BIT(9)
|
|
+#define REG_SECENG_GMAC_0_CTRL_0_INT BIT(8)
|
|
+#define REG_SECENG_GMAC_0_CTRL_0_EN BIT(2)
|
|
+#define REG_SECENG_GMAC_0_CTRL_0_TRIG_1T BIT(1)
|
|
+#define REG_SECENG_GMAC_0_CTRL_0_BUSY BIT(0)
|
|
+
|
|
+//se_gmac_0_lca
|
|
+#define REG_SECENG_GMAC_0_LCA 1284
|
|
+
|
|
+//se_gmac_0_status
|
|
+#define REG_SECENG_GMAC_0_STATUS 1288
|
|
+
|
|
+//se_gmac_0_ctrl_prot
|
|
+#define REG_SECENG_GMAC_0_CTRL_PROT 1532
|
|
+#define REG_SECENG_GMAC_0_CTRL_PROT_ID1_EN BIT(2)
|
|
+#define REG_SECENG_GMAC_0_CTRL_PROT_ID0_EN BIT(1)
|
|
+
|
|
+//se_ctrl_prot_rd
|
|
+#define REG_SECENG_CTRL_PROT_RD 3840
|
|
+#define REG_SECENG_CTRL_PROT_RD_DBG_DIS BIT(31)
|
|
+#define REG_SECENG_CTRL_PROT_RD_GMAC_ID1_EN_RD BIT(11)
|
|
+#define REG_SECENG_CTRL_PROT_RD_GMAC_ID0_EN_RD BIT(10)
|
|
+#define REG_SECENG_CTRL_PROT_RD_CDET_ID1_EN_RD BIT(9)
|
|
+#define REG_SECENG_CTRL_PROT_RD_CDET_ID0_EN_RD BIT(8)
|
|
+#define REG_SECENG_CTRL_PROT_RD_PKA_ID1_EN_RD BIT(7)
|
|
+#define REG_SECENG_CTRL_PROT_RD_PKA_ID0_EN_RD BIT(6)
|
|
+#define REG_SECENG_CTRL_PROT_RD_TRNG_ID1_EN_RD BIT(5)
|
|
+#define REG_SECENG_CTRL_PROT_RD_TRNG_ID0_EN_RD BIT(4)
|
|
+#define REG_SECENG_CTRL_PROT_RD_AES_ID1_EN_RD BIT(3)
|
|
+#define REG_SECENG_CTRL_PROT_RD_AES_ID0_EN_RD BIT(2)
|
|
+#define REG_SECENG_CTRL_PROT_RD_SHA_ID1_EN_RD BIT(1)
|
|
+#define REG_SECENG_CTRL_PROT_RD_SHA_ID0_EN_RD BIT(0)
|
|
+
|
|
+struct bflb_seceng {
|
|
+ struct mutex lock;
|
|
+ struct device *dev;
|
|
+ void __iomem *base;
|
|
+ struct regmap *map;
|
|
+ unsigned int initialised;
|
|
+
|
|
+ struct hwrng hwrng;
|
|
+};
|
|
+
|
|
+struct bflb_seceng_ctx {
|
|
+ struct bflb_seceng *seceng;
|
|
+};
|
|
+
|
|
+struct regmap_config bflb_seceng_regmap_config = {
|
|
+ .reg_bits = 32,
|
|
+ .val_bits = 32,
|
|
+ .reg_stride = 4,
|
|
+ .cache_type = REGCACHE_FLAT,
|
|
+ .max_register = 512 * sizeof(u32),
|
|
+ .num_reg_defaults_raw = 512,
|
|
+ .use_relaxed_mmio = true,
|
|
+ .use_raw_spinlock = true,
|
|
+};
|
|
+
|
|
+static struct bflb_seceng *bflb_seceng_dev;
|
|
+
|
|
+static void bflb_seceng_trng_wait_ready(void)
|
|
+{
|
|
+ while (readl_relaxed(bflb_seceng_dev->base + REG_SECENG_TRNG_0_CTRL_0) &
|
|
+ REG_SECENG_TRNG_0_CTRL_0_BUSY) {
|
|
+ dev_dbg(bflb_seceng_dev->dev, "Waiting for TRNG ready");
|
|
+ schedule();
|
|
+ }
|
|
+}
|
|
+
|
|
+static void bflb_seceng_trng_init(void)
|
|
+{
|
|
+ regmap_update_bits(bflb_seceng_dev->map, REG_SECENG_TRNG_0_CTRL_0,
|
|
+ REG_SECENG_TRNG_0_CTRL_0_EN | REG_SECENG_TRNG_0_CTRL_0_INT_CLR_1T,
|
|
+ FIELD_PREP(REG_SECENG_TRNG_0_CTRL_0_EN, 1) |
|
|
+ FIELD_PREP(REG_SECENG_TRNG_0_CTRL_0_INT_CLR_1T, 1));
|
|
+
|
|
+ bflb_seceng_trng_wait_ready();
|
|
+}
|
|
+
|
|
+static void bflb_seceng_trng_refresh(void)
|
|
+{
|
|
+ regmap_update_bits(bflb_seceng_dev->map, REG_SECENG_TRNG_0_CTRL_0,
|
|
+ REG_SECENG_TRNG_0_CTRL_0_DOUT_CLR_1T,
|
|
+ FIELD_PREP(REG_SECENG_TRNG_0_CTRL_0_DOUT_CLR_1T, 1)); //Clear DOUT
|
|
+
|
|
+ bflb_seceng_trng_wait_ready();
|
|
+
|
|
+ regmap_update_bits(bflb_seceng_dev->map, REG_SECENG_TRNG_0_CTRL_0,
|
|
+ REG_SECENG_TRNG_0_CTRL_0_DOUT_CLR_1T,
|
|
+ FIELD_PREP(REG_SECENG_TRNG_0_CTRL_0_DOUT_CLR_1T, 0)); //Reset clear DOUT
|
|
+
|
|
+ regmap_update_bits(bflb_seceng_dev->map,
|
|
+ REG_SECENG_TRNG_0_CTRL_0, REG_SECENG_TRNG_0_CTRL_0_TRIG_1T,
|
|
+ FIELD_PREP(REG_SECENG_TRNG_0_CTRL_0_TRIG_1T, 1)); //Force TRNG refresh
|
|
+
|
|
+ bflb_seceng_trng_wait_ready();
|
|
+
|
|
+ regmap_update_bits(bflb_seceng_dev->map, REG_SECENG_TRNG_0_CTRL_0,
|
|
+ REG_SECENG_TRNG_0_CTRL_0_INT_CLR_1T,
|
|
+ FIELD_PREP(REG_SECENG_TRNG_0_CTRL_0_INT_CLR_1T, 1)); //Clear INT
|
|
+
|
|
+ dev_dbg(bflb_seceng_dev->dev, "Refreshed TRNG");
|
|
+}
|
|
+
|
|
+static unsigned int bflb_seceng_trng_read_dout(struct bflb_seceng *seceng,
|
|
+ unsigned int doutreg)
|
|
+{
|
|
+ return readl_relaxed(seceng->base + REG_SECENG_TRNG_0_DOUT_0 +
|
|
+ (doutreg * 4));
|
|
+}
|
|
+
|
|
+static inline unsigned int bflb_seceng_trng_read32(void)
|
|
+{
|
|
+ static u8 doutreg = 8;
|
|
+ u32 val;
|
|
+
|
|
+ if (doutreg >= 8) {
|
|
+ //If we have read all available registers (of starting anew),
|
|
+ //refresh them and start again
|
|
+ doutreg = 0;
|
|
+
|
|
+ bflb_seceng_trng_refresh();
|
|
+ }
|
|
+
|
|
+ dev_dbg(bflb_seceng_dev->dev, "Selected TRNG DOUT register %u", doutreg);
|
|
+
|
|
+ //Read selected register
|
|
+ val = bflb_seceng_trng_read_dout(bflb_seceng_dev, doutreg);
|
|
+ doutreg++; //Move on to next register
|
|
+
|
|
+ dev_dbg(bflb_seceng_dev->dev, "TRNG DOUT register produced %u", val);
|
|
+
|
|
+ return val;
|
|
+}
|
|
+
|
|
+static inline u8 bflb_seceng_trng_read8(void)
|
|
+{
|
|
+ static unsigned int lastread;
|
|
+ static u8 shift = 4;
|
|
+
|
|
+ if (shift == 4) {
|
|
+ shift = 0;
|
|
+
|
|
+ lastread = bflb_seceng_trng_read32();
|
|
+ }
|
|
+
|
|
+ return (lastread >> (shift++ * 8)) & 0xFF;
|
|
+}
|
|
+
|
|
+static void bflb_seceng_trng_fill_buffer(u8 *buff, unsigned long bufflen)
|
|
+{
|
|
+ unsigned long i;
|
|
+
|
|
+ for (i = 0; i < bufflen; i++)
|
|
+ buff[i] = bflb_seceng_trng_read8();
|
|
+}
|
|
+
|
|
+static int bflb_seceng_trng_hwrng_read(struct hwrng *rng, void *data,
|
|
+ size_t max, bool wait)
|
|
+{
|
|
+ //Currently ignoring wait
|
|
+
|
|
+ mutex_lock(&bflb_seceng_dev->lock);
|
|
+
|
|
+ dev_dbg(bflb_seceng_dev->dev, "Starting TRNG hwrng read for %lu bytes...",
|
|
+ max);
|
|
+
|
|
+ bflb_seceng_trng_fill_buffer(data, max);
|
|
+
|
|
+ mutex_unlock(&bflb_seceng_dev->lock);
|
|
+
|
|
+ //We're always going to fill the buffer, so just return what was asked for
|
|
+ return max;
|
|
+}
|
|
+
|
|
+static int bflb_seceng_trng_crypto_generate(struct crypto_rng *tfm,
|
|
+ const u8 *src, unsigned int slen, u8 *dstn, unsigned int dlen)
|
|
+{
|
|
+ struct bflb_seceng_ctx *ctx = crypto_rng_ctx(tfm);
|
|
+ struct bflb_seceng *seceng = ctx->seceng;
|
|
+
|
|
+ mutex_lock(&seceng->lock);
|
|
+
|
|
+ dev_dbg(seceng->dev,
|
|
+ "Starting TRNG crypto buffer filling read for %u bytes...", dlen);
|
|
+
|
|
+ bflb_seceng_trng_fill_buffer(dstn, dlen);
|
|
+
|
|
+ mutex_unlock(&seceng->lock);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int bflb_seceng_trng_crypto_seed(struct crypto_rng *tfm, const u8 *seed,
|
|
+ unsigned int slen)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int bflb_seceng_trng_crypto_init(struct crypto_tfm *tfm)
|
|
+{
|
|
+ struct bflb_seceng_ctx *ctx = crypto_tfm_ctx(tfm);
|
|
+
|
|
+ ctx->seceng = bflb_seceng_dev;
|
|
+
|
|
+ //Skip actual initialisation of the hardware if we have already done so
|
|
+ if (bflb_seceng_dev->initialised)
|
|
+ return 0;
|
|
+
|
|
+ bflb_seceng_trng_init();
|
|
+
|
|
+ dev_dbg(bflb_seceng_dev->dev, "Initialised TRNG via crypto");
|
|
+
|
|
+ bflb_seceng_dev->initialised = 1;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int bflb_seceng_trng_hwrng_init(struct hwrng *rng)
|
|
+{
|
|
+ if (bflb_seceng_dev->initialised)
|
|
+ return 0;
|
|
+
|
|
+ bflb_seceng_trng_init();
|
|
+
|
|
+ dev_dbg(bflb_seceng_dev->dev, "Initialised TRNG via hwrng");
|
|
+
|
|
+ bflb_seceng_dev->initialised = 1;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static struct rng_alg bflb_seceng_trng_alg = {
|
|
+ .generate = bflb_seceng_trng_crypto_generate,
|
|
+ .seed = bflb_seceng_trng_crypto_seed,
|
|
+ .seedsize = 0,
|
|
+ .base = {
|
|
+ .cra_name = "stdrng",
|
|
+ .cra_driver_name = "bflb-seceng",
|
|
+ .cra_flags = CRYPTO_ALG_TYPE_RNG,
|
|
+ .cra_priority = 300,
|
|
+ .cra_ctxsize = sizeof(struct bflb_seceng_ctx),
|
|
+ .cra_module = THIS_MODULE,
|
|
+ .cra_init = bflb_seceng_trng_crypto_init,
|
|
+ }
|
|
+};
|
|
+
|
|
+static struct hwrng bflb_hwrng = {
|
|
+ .name = "bflb-seceng",
|
|
+ .init = bflb_seceng_trng_hwrng_init,
|
|
+ .read = bflb_seceng_trng_hwrng_read,
|
|
+};
|
|
+
|
|
+static int bflb_seceng_probe(struct platform_device *pdev)
|
|
+{
|
|
+ struct bflb_seceng *seceng;
|
|
+ int ret;
|
|
+
|
|
+ seceng = devm_kzalloc(&pdev->dev, sizeof(*seceng), GFP_KERNEL);
|
|
+
|
|
+ if (!seceng)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ seceng->dev = &pdev->dev;
|
|
+
|
|
+ platform_set_drvdata(pdev, seceng);
|
|
+ mutex_init(&seceng->lock);
|
|
+
|
|
+ seceng->base = devm_platform_ioremap_resource(pdev, 0);
|
|
+
|
|
+ if (IS_ERR(seceng->base))
|
|
+ return PTR_ERR(seceng->base);
|
|
+
|
|
+ seceng->map = devm_regmap_init_mmio(&pdev->dev, seceng->base,
|
|
+ &bflb_seceng_regmap_config);
|
|
+
|
|
+ if (IS_ERR(seceng->map))
|
|
+ return dev_err_probe(&pdev->dev, PTR_ERR(seceng->map),
|
|
+ "Failed to create regmap\n");
|
|
+
|
|
+ bflb_seceng_dev = seceng; //Assign driver static
|
|
+
|
|
+ ret = crypto_register_rng(&bflb_seceng_trng_alg);
|
|
+
|
|
+ if (ret)
|
|
+ dev_err_probe(&pdev->dev, ret,
|
|
+ "Failed to register as a crypto random number generator\n");
|
|
+
|
|
+ seceng->hwrng = bflb_hwrng;
|
|
+
|
|
+ ret = hwrng_register(&seceng->hwrng);
|
|
+
|
|
+ if (ret)
|
|
+ dev_err_probe(&pdev->dev, ret,
|
|
+ "Failed to register as a hardware random number generator\n");
|
|
+
|
|
+ dev_info(&pdev->dev, "Bouffalo Lab Secure Engine");
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int bflb_seceng_remove(struct platform_device *pdev)
|
|
+{
|
|
+ hwrng_unregister(&bflb_seceng_dev->hwrng);
|
|
+ crypto_unregister_rng(&bflb_seceng_trng_alg);
|
|
+
|
|
+ bflb_seceng_dev = NULL;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static const struct of_device_id __maybe_unused bflb_seceng_of_match[] = {
|
|
+ { .compatible = "bflb,seceng", .data = (const void *)0, },
|
|
+ {}
|
|
+};
|
|
+MODULE_DEVICE_TABLE(of, bflb_seceng_of_match);
|
|
+
|
|
+static struct platform_driver bflb_seceng_driver = {
|
|
+ .probe = bflb_seceng_probe,
|
|
+ .remove = bflb_seceng_remove,
|
|
+ .driver = {
|
|
+ .name = "bflb-seceng",
|
|
+ .of_match_table = bflb_seceng_of_match,
|
|
+ .suppress_bind_attrs = true,
|
|
+ }
|
|
+};
|
|
+module_platform_driver(bflb_seceng_driver);
|
|
+
|
|
+MODULE_DESCRIPTION("Bouffalo BL808 Secure Engine driver");
|
|
+MODULE_AUTHOR("Alexander Horner <contact@alexhorner.cc>");
|
|
+MODULE_LICENSE("GPL v2");
|
|
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
|
|
index 7d5f5458c72e..9120cd4b761f 100644
|
|
--- a/drivers/pinctrl/Kconfig
|
|
+++ b/drivers/pinctrl/Kconfig
|
|
@@ -127,6 +127,22 @@ config PINCTRL_AXP209
|
|
selected.
|
|
Say Y to enable pinctrl and GPIO support for the AXP209 PMIC.
|
|
|
|
+config PINCTRL_BFLB_GPIO
|
|
+ tristate "Bouffalo Lab SoC GPIO pin controller driver"
|
|
+ depends on SOC_BOUFFALOLAB
|
|
+ select PINMUX
|
|
+ select GPIOLIB
|
|
+ select GPIOLIB_IRQCHIP
|
|
+ select GENERIC_PINCONF
|
|
+ select GENERIC_PINCTRL_GROUPS
|
|
+ select GENERIC_PINMUX_FUNCTIONS
|
|
+ select OF_GPIO
|
|
+ help
|
|
+ This is the driver for the GPIO controller found on Bouffalo Lab RISC-V SoCs.
|
|
+
|
|
+ This driver can also be built as a module. If so, the module
|
|
+ will be called pinctrl-bflb-gpio.
|
|
+
|
|
config PINCTRL_BM1880
|
|
bool "Bitmain BM1880 Pinctrl driver"
|
|
depends on OF && (ARCH_BITMAIN || COMPILE_TEST)
|
|
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
|
|
index d5939840bb2a..9f7c89ed4bb4 100644
|
|
--- a/drivers/pinctrl/Makefile
|
|
+++ b/drivers/pinctrl/Makefile
|
|
@@ -16,6 +16,7 @@ obj-$(CONFIG_PINCTRL_AS3722) += pinctrl-as3722.o
|
|
obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o
|
|
obj-$(CONFIG_PINCTRL_AT91PIO4) += pinctrl-at91-pio4.o
|
|
obj-$(CONFIG_PINCTRL_AXP209) += pinctrl-axp209.o
|
|
+obj-$(CONFIG_PINCTRL_BFLB_GPIO) += pinctrl-bflb.o
|
|
obj-$(CONFIG_PINCTRL_BM1880) += pinctrl-bm1880.o
|
|
obj-$(CONFIG_PINCTRL_CY8C95X0) += pinctrl-cy8c95x0.o
|
|
obj-$(CONFIG_PINCTRL_DA850_PUPD) += pinctrl-da850-pupd.o
|
|
diff --git a/drivers/pinctrl/pinctrl-bflb.c b/drivers/pinctrl/pinctrl-bflb.c
|
|
new file mode 100644
|
|
index 000000000000..4223fcc18ed5
|
|
--- /dev/null
|
|
+++ b/drivers/pinctrl/pinctrl-bflb.c
|
|
@@ -0,0 +1,719 @@
|
|
+// SPDX-License-Identifier: GPL-2.0-only
|
|
+/*
|
|
+ * Bouffalo Lab SoC pinctrl+GPIO+external IRQ driver
|
|
+ *
|
|
+ * Based on: pinctrl-apple-gpio.c
|
|
+ * Copyright (C) The Asahi Linux Contributors
|
|
+ * Copyright (C) 2020 Corellium LLC
|
|
+ *
|
|
+ * Based on: pinctrl-pistachio.c
|
|
+ * Copyright (C) 2014 Imagination Technologies Ltd.
|
|
+ * Copyright (C) 2014 Google, Inc.
|
|
+ */
|
|
+
|
|
+#include <linux/bitfield.h>
|
|
+#include <linux/bits.h>
|
|
+#include <linux/gpio/driver.h>
|
|
+#include <linux/interrupt.h>
|
|
+#include <linux/irq.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/of.h>
|
|
+#include <linux/of_irq.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/regmap.h>
|
|
+
|
|
+#include <linux/pinctrl/consumer.h>
|
|
+#include <linux/pinctrl/pinconf-generic.h>
|
|
+#include <linux/pinctrl/pinctrl.h>
|
|
+#include <linux/pinctrl/pinmux.h>
|
|
+
|
|
+#include "pinctrl-utils.h"
|
|
+#include "core.h"
|
|
+#include "pinmux.h"
|
|
+
|
|
+struct bflb_gpio_pinctrl {
|
|
+ struct device *dev;
|
|
+ struct pinctrl_dev *pctldev;
|
|
+
|
|
+ void __iomem *base;
|
|
+ struct regmap *map;
|
|
+
|
|
+ struct pinctrl_desc pinctrl_desc;
|
|
+ struct gpio_chip gpio_chip;
|
|
+
|
|
+ void *irqsunmasked;
|
|
+ u8 irqgrps[];
|
|
+};
|
|
+
|
|
+//Register indexing
|
|
+#define REG_GPIO(x) (4 * (x))
|
|
+
|
|
+//Register map
|
|
+#define REG_GPIOx_MODE GENMASK(31, 30)
|
|
+#define REG_GPIOx_I BIT(28)
|
|
+#define REG_GPIOx_CLR BIT(26)
|
|
+#define REG_GPIOx_SET BIT(25)
|
|
+#define REG_GPIOx_O BIT(24)
|
|
+#define REG_GPIOx_INT_MASK BIT(22)
|
|
+#define REG_GPIOx_INT_STAT BIT(21)
|
|
+#define REG_GPIOx_INT_CLR BIT(20)
|
|
+#define REG_GPIOx_INT_MODE_SET GENMASK(29, 16)
|
|
+#define REG_GPIOx_FUNC_SEL GENMASK(12, 8)
|
|
+#define REG_GPIOx_OE BIT(6)
|
|
+#define REG_GPIOx_PD BIT(5)
|
|
+#define REG_GPIOx_PU BIT(4)
|
|
+#define REG_GPIOx_DRV GENMASK(3, 2)
|
|
+#define REG_GPIOx_SMT BIT(1)
|
|
+#define REG_GPIOx_IE BIT(0)
|
|
+
|
|
+//Interrupt trigger modes
|
|
+#define BFLB_IRQ_MODE_SYNC_EDGE_FALLING 0
|
|
+#define BFLB_IRQ_MODE_SYNC_EDGE_RISING 1
|
|
+#define BFLB_IRQ_MODE_SYNC_LEVEL_LOW 2
|
|
+#define BFLB_IRQ_MODE_SYNC_LEVEL_HIGH 3
|
|
+#define BFLB_IRQ_MODE_SYNC_EDGE_BOTH 4
|
|
+
|
|
+#define BFLB_IRQ_MODE_ASYNC_EDGE_FALLING 8
|
|
+#define BFLB_IRQ_MODE_ASYNC_EDGE_RISING 9
|
|
+#define BFLB_IRQ_MODE_ASYNC_LEVEL_LOW 10
|
|
+#define BFLB_IRQ_MODE_ASYNC_LEVEL_HIGH 11
|
|
+
|
|
+static const char * const pinmux_functions[] = {
|
|
+ //AH: As taken from smaeul's pinctrl-bflb.c for U-Boot
|
|
+ [0] = "sdh",
|
|
+ [1] = "spi0",
|
|
+ [2] = "flash",
|
|
+ [3] = "i2s",
|
|
+ [4] = "pdm",
|
|
+ [5] = "i2c0",
|
|
+ [6] = "i2c1",
|
|
+ [7] = "uart",
|
|
+ [8] = "emac",
|
|
+ [9] = "cam",
|
|
+ [10] = "analog",
|
|
+ [11] = "gpio",
|
|
+ [16] = "pwm0",
|
|
+ [17] = "pwm1",
|
|
+ [18] = "spi1", // mm_spi
|
|
+ [19] = "i2c2", // mm_i2c0
|
|
+ [20] = "i2c3", // mm_i2c1
|
|
+ [21] = "mm_uart",
|
|
+ [22] = "dbi_b",
|
|
+ [23] = "dbi_c",
|
|
+ [24] = "dpi",
|
|
+ [25] = "jtag_lp",
|
|
+ [26] = "jtag_m0",
|
|
+ [27] = "jtag_d0",
|
|
+ [31] = "clock",
|
|
+};
|
|
+
|
|
+struct regmap_config regmap_config = {
|
|
+ .reg_bits = 32,
|
|
+ .val_bits = 32,
|
|
+ .reg_stride = 4,
|
|
+ .cache_type = REGCACHE_FLAT,
|
|
+ .max_register = 512 * sizeof(u32),
|
|
+ .num_reg_defaults_raw = 512,
|
|
+ .use_relaxed_mmio = true,
|
|
+ .use_raw_spinlock = true,
|
|
+};
|
|
+
|
|
+//AH: Set raw gpio config register bits based on mask
|
|
+static void bflb_gpio_set_reg(struct bflb_gpio_pinctrl *pctl, unsigned int pin,
|
|
+ u32 mask, u32 value)
|
|
+{
|
|
+ regmap_update_bits(pctl->map, REG_GPIO(pin), mask, value);
|
|
+}
|
|
+
|
|
+//AH: Get raw gpio config register bits
|
|
+static u32 bflb_gpio_get_reg(struct bflb_gpio_pinctrl *pctl, unsigned int pin)
|
|
+{
|
|
+ int ret;
|
|
+ u32 val;
|
|
+
|
|
+ ret = regmap_read(pctl->map, REG_GPIO(pin), &val);
|
|
+
|
|
+ if (ret)
|
|
+ return 0;
|
|
+
|
|
+ return val;
|
|
+}
|
|
+
|
|
+/* Pin controller functions */
|
|
+
|
|
+static const struct pinctrl_ops bflb_gpio_pinctrl_ops = {
|
|
+ .get_groups_count = pinctrl_generic_get_group_count,
|
|
+ .get_group_name = pinctrl_generic_get_group_name,
|
|
+ .get_group_pins = pinctrl_generic_get_group_pins,
|
|
+ .dt_node_to_map = pinconf_generic_dt_node_to_map_group,
|
|
+ .dt_free_map = pinconf_generic_dt_free_map,
|
|
+};
|
|
+
|
|
+/* Pin multiplexer functions */
|
|
+
|
|
+//AH: Configure gpio modes and features
|
|
+static int bflb_gpio_pinmux_set(struct pinctrl_dev *pctldev, unsigned int func,
|
|
+ unsigned int group)
|
|
+{
|
|
+ struct bflb_gpio_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
|
|
+
|
|
+ bflb_gpio_set_reg(pctl, group, REG_GPIOx_FUNC_SEL,
|
|
+ FIELD_PREP(REG_GPIOx_FUNC_SEL, func));
|
|
+
|
|
+ dev_dbg(pctl->dev, "Pin %u set to function %u", group, func);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static const struct pinmux_ops bflb_gpio_pinmux_ops = {
|
|
+ .get_functions_count = pinmux_generic_get_function_count,
|
|
+ .get_function_name = pinmux_generic_get_function_name,
|
|
+ .get_function_groups = pinmux_generic_get_function_groups,
|
|
+ .set_mux = bflb_gpio_pinmux_set,
|
|
+ .strict = true,
|
|
+};
|
|
+
|
|
+/* GPIO chip functions */
|
|
+
|
|
+//AH: Get the current gpio direction
|
|
+static int bflb_gpio_get_direction(struct gpio_chip *chip,
|
|
+ unsigned int offset)
|
|
+{
|
|
+ struct bflb_gpio_pinctrl *pctl = gpiochip_get_data(chip);
|
|
+ unsigned int reg = bflb_gpio_get_reg(pctl, offset);
|
|
+
|
|
+ if (FIELD_GET(REG_GPIOx_OE, reg) == 1 &&
|
|
+ FIELD_GET(REG_GPIOx_IE, reg) == 0) {
|
|
+ return GPIO_LINE_DIRECTION_OUT;
|
|
+ } else if (FIELD_GET(REG_GPIOx_IE, reg) == 1 &&
|
|
+ FIELD_GET(REG_GPIOx_OE, reg) == 0) {
|
|
+ return GPIO_LINE_DIRECTION_IN;
|
|
+ }
|
|
+
|
|
+ return -EIO;
|
|
+}
|
|
+
|
|
+//AH: Get the incoming input or outgoing output value for the specified GPIO
|
|
+static int bflb_gpio_get(struct gpio_chip *chip, unsigned int offset)
|
|
+{
|
|
+ struct bflb_gpio_pinctrl *pctl = gpiochip_get_data(chip);
|
|
+ unsigned int reg = bflb_gpio_get_reg(pctl, offset);
|
|
+
|
|
+ if (FIELD_GET(REG_GPIOx_OE, reg) == 1 &&
|
|
+ FIELD_GET(REG_GPIOx_IE, reg) == 0) {
|
|
+ reg = readl_relaxed(pctl->base + REG_GPIO(offset));
|
|
+ return !!(reg & REG_GPIOx_O);
|
|
+ } else if (FIELD_GET(REG_GPIOx_IE, reg) == 1 &&
|
|
+ FIELD_GET(REG_GPIOx_OE, reg) == 0) {
|
|
+ reg = readl_relaxed(pctl->base + REG_GPIO(offset));
|
|
+ return !!(reg & REG_GPIOx_I);
|
|
+ }
|
|
+
|
|
+ return -EIO;
|
|
+}
|
|
+
|
|
+//AH: Set the specified GPIO's output state
|
|
+static void bflb_gpio_set(struct gpio_chip *chip, unsigned int offset,
|
|
+ int value)
|
|
+{
|
|
+ struct bflb_gpio_pinctrl *pctl = gpiochip_get_data(chip);
|
|
+
|
|
+ bflb_gpio_set_reg(pctl, offset, REG_GPIOx_O, value ?
|
|
+ FIELD_PREP(REG_GPIOx_O, 1) : 0);
|
|
+
|
|
+ dev_dbg(pctl->dev, "Pin %u set to value %u", offset, value);
|
|
+}
|
|
+
|
|
+//AH: Set the specified gpio direction to input
|
|
+static int bflb_gpio_direction_input(struct gpio_chip *chip,
|
|
+ unsigned int offset)
|
|
+{
|
|
+ struct bflb_gpio_pinctrl *pctl = gpiochip_get_data(chip);
|
|
+
|
|
+ bflb_gpio_set_reg(pctl, offset, REG_GPIOx_OE | REG_GPIOx_IE | REG_GPIOx_SMT,
|
|
+ FIELD_PREP(REG_GPIOx_OE, 0) | FIELD_PREP(REG_GPIOx_IE, 1) |
|
|
+ FIELD_PREP(REG_GPIOx_SMT, 1));
|
|
+
|
|
+ dev_dbg(pctl->dev, "Pin %u set to direction input", offset);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+//AH: Set the specified gpio direction to output
|
|
+static int bflb_gpio_direction_output(struct gpio_chip *chip,
|
|
+ unsigned int offset, int value)
|
|
+{
|
|
+ struct bflb_gpio_pinctrl *pctl = gpiochip_get_data(chip);
|
|
+
|
|
+ bflb_gpio_set_reg(pctl, offset, REG_GPIOx_PD | REG_GPIOx_PU | REG_GPIOx_OE |
|
|
+ REG_GPIOx_IE | REG_GPIOx_SMT | REG_GPIOx_MODE,
|
|
+ FIELD_PREP(REG_GPIOx_PD, 0) | FIELD_PREP(REG_GPIOx_PU, 0) |
|
|
+ FIELD_PREP(REG_GPIOx_OE, 1) | FIELD_PREP(REG_GPIOx_IE, 0) |
|
|
+ FIELD_PREP(REG_GPIOx_SMT, 1) | FIELD_PREP(REG_GPIOx_MODE, 0));
|
|
+
|
|
+ dev_dbg(pctl->dev, "Pin %u set to direction output", offset);
|
|
+
|
|
+ bflb_gpio_set(chip, offset, value); //Set the initially passed value
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+//AH: Configure pin electrical characteristics
|
|
+static int bflb_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
|
|
+ unsigned long config)
|
|
+{
|
|
+ struct bflb_gpio_pinctrl *pctl = gpiochip_get_data(chip);
|
|
+ enum pin_config_param param = pinconf_to_config_param(config);
|
|
+ unsigned int arg = pinconf_to_config_argument(config);
|
|
+
|
|
+ switch (param) {
|
|
+ case PIN_CONFIG_BIAS_DISABLE:
|
|
+ bflb_gpio_set_reg(pctl, offset, REG_GPIOx_PD | REG_GPIOx_PU,
|
|
+ FIELD_PREP(REG_GPIOx_PD, 0) | FIELD_PREP(REG_GPIOx_PU, 0));
|
|
+ break;
|
|
+
|
|
+ case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
|
|
+ if (arg) {
|
|
+ bflb_gpio_set_reg(pctl, offset, REG_GPIOx_PD | REG_GPIOx_PU,
|
|
+ FIELD_PREP(REG_GPIOx_PD, 0) | FIELD_PREP(REG_GPIOx_PU, 0));
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case PIN_CONFIG_BIAS_PULL_DOWN:
|
|
+ if (arg) {
|
|
+ bflb_gpio_set_reg(pctl, offset, REG_GPIOx_PD | REG_GPIOx_PU,
|
|
+ FIELD_PREP(REG_GPIOx_PD, 1) | FIELD_PREP(REG_GPIOx_PU, 0));
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case PIN_CONFIG_BIAS_PULL_UP:
|
|
+ if (arg) {
|
|
+ bflb_gpio_set_reg(pctl, offset, REG_GPIOx_PD | REG_GPIOx_PU,
|
|
+ FIELD_PREP(REG_GPIOx_PD, 0) | FIELD_PREP(REG_GPIOx_PU, 1));
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
|
|
+ bflb_gpio_set_reg(pctl, offset, REG_GPIOx_PD | REG_GPIOx_PU |
|
|
+ REG_GPIOx_IE | REG_GPIOx_OE, FIELD_PREP(REG_GPIOx_PD, 0) |
|
|
+ FIELD_PREP(REG_GPIOx_PU, 0) | FIELD_PREP(REG_GPIOx_IE, 0) |
|
|
+ FIELD_PREP(REG_GPIOx_OE, 0));
|
|
+ break;
|
|
+
|
|
+ case PIN_CONFIG_INPUT_ENABLE:
|
|
+ bflb_gpio_set_reg(pctl, offset, REG_GPIOx_IE,
|
|
+ FIELD_PREP(REG_GPIOx_IE, !!arg));
|
|
+ break;
|
|
+
|
|
+ case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
|
|
+ bflb_gpio_set_reg(pctl, offset, REG_GPIOx_SMT,
|
|
+ FIELD_PREP(REG_GPIOx_SMT, !!arg));
|
|
+ break;
|
|
+
|
|
+ case PIN_CONFIG_OUTPUT:
|
|
+ bflb_gpio_set_reg(pctl, offset, REG_GPIOx_OE | REG_GPIOx_O,
|
|
+ FIELD_PREP(REG_GPIOx_OE, 1) | FIELD_PREP(REG_GPIOx_O, !!arg));
|
|
+ break;
|
|
+
|
|
+ case PIN_CONFIG_OUTPUT_ENABLE:
|
|
+ bflb_gpio_set_reg(pctl, offset, REG_GPIOx_OE,
|
|
+ FIELD_PREP(REG_GPIOx_OE, 1));
|
|
+ break;
|
|
+
|
|
+ default: return -ENOTSUPP;
|
|
+ }
|
|
+
|
|
+ dev_dbg(pctl->dev, "Pin %u config set to %lu (param %u, arg %u)", offset,
|
|
+ config, param, arg);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* IRQ chip functions */
|
|
+
|
|
+//AH: Clear the interrupt for the specified GPIO
|
|
+static void bflb_gpio_irq_ack(struct irq_data *data)
|
|
+{
|
|
+ struct bflb_gpio_pinctrl *pctl =
|
|
+ gpiochip_get_data(irq_data_get_irq_chip_data(data));
|
|
+
|
|
+ bflb_gpio_set_reg(pctl, data->hwirq, REG_GPIOx_INT_CLR,
|
|
+ FIELD_PREP(REG_GPIOx_INT_CLR, 1));
|
|
+
|
|
+ bflb_gpio_set_reg(pctl, data->hwirq, REG_GPIOx_INT_CLR,
|
|
+ FIELD_PREP(REG_GPIOx_INT_CLR, 0));
|
|
+
|
|
+ dev_dbg(pctl->dev, "Pin %lu IRQ ACK", data->hwirq);
|
|
+}
|
|
+
|
|
+//AH: Find the correct value for the type of interrupts we want to receive
|
|
+//for a GPIO
|
|
+static unsigned int bflb_gpio_irq_type(unsigned int type)
|
|
+{
|
|
+ unsigned int selected;
|
|
+
|
|
+ switch (type & IRQ_TYPE_SENSE_MASK) {
|
|
+
|
|
+ case IRQ_TYPE_EDGE_RISING:
|
|
+ selected = BFLB_IRQ_MODE_SYNC_EDGE_RISING;
|
|
+ break;
|
|
+
|
|
+ case IRQ_TYPE_EDGE_FALLING:
|
|
+ selected = BFLB_IRQ_MODE_SYNC_EDGE_FALLING;
|
|
+ break;
|
|
+
|
|
+ case IRQ_TYPE_EDGE_BOTH:
|
|
+ selected = BFLB_IRQ_MODE_SYNC_EDGE_BOTH;
|
|
+ break;
|
|
+
|
|
+ case IRQ_TYPE_LEVEL_HIGH:
|
|
+ selected = BFLB_IRQ_MODE_SYNC_LEVEL_HIGH;
|
|
+ break;
|
|
+
|
|
+ case IRQ_TYPE_LEVEL_LOW:
|
|
+ selected = BFLB_IRQ_MODE_SYNC_LEVEL_LOW;
|
|
+ break;
|
|
+
|
|
+ //No "off" available on BL808, set to default IRQ_TYPE_EDGE_FALLING and
|
|
+ //then we'll need to mask
|
|
+ default:
|
|
+ selected = BFLB_IRQ_MODE_SYNC_EDGE_FALLING;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return selected;
|
|
+}
|
|
+
|
|
+//AH: Disable the specified GPIO's interrupt
|
|
+static void bflb_gpio_irq_mask(struct irq_data *data)
|
|
+{
|
|
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
|
|
+ struct bflb_gpio_pinctrl *pctl = gpiochip_get_data(gc);
|
|
+
|
|
+ bflb_gpio_set_reg(pctl, data->hwirq, REG_GPIOx_INT_MASK,
|
|
+ FIELD_PREP(REG_GPIOx_INT_MASK, 1));
|
|
+
|
|
+ clear_bit(data->hwirq, pctl->irqsunmasked);
|
|
+ gpiochip_disable_irq(gc, data->hwirq);
|
|
+
|
|
+ dev_dbg(pctl->dev, "Pin %lu IRQ Mask", data->hwirq);
|
|
+}
|
|
+
|
|
+//AH: Enable the specified GPIO's interrupt
|
|
+static void bflb_gpio_irq_unmask(struct irq_data *data)
|
|
+{
|
|
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
|
|
+ struct bflb_gpio_pinctrl *pctl = gpiochip_get_data(gc);
|
|
+ unsigned int irqtype = bflb_gpio_irq_type(irqd_get_trigger_type(data));
|
|
+
|
|
+ gpiochip_enable_irq(gc, data->hwirq);
|
|
+ set_bit(data->hwirq, pctl->irqsunmasked);
|
|
+
|
|
+ bflb_gpio_set_reg(pctl, data->hwirq, REG_GPIOx_INT_MASK |
|
|
+ REG_GPIOx_INT_MODE_SET, FIELD_PREP(REG_GPIOx_INT_MASK, 0) |
|
|
+ FIELD_PREP(REG_GPIOx_INT_MODE_SET, irqtype));
|
|
+
|
|
+ dev_dbg(pctl->dev, "Pin %lu IRQ Unmask", data->hwirq);
|
|
+}
|
|
+
|
|
+//AH: Initialise the specified GPIO's interrupt
|
|
+static unsigned int bflb_gpio_irq_startup(struct irq_data *data)
|
|
+{
|
|
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
|
|
+ struct bflb_gpio_pinctrl *pctl = gpiochip_get_data(chip);
|
|
+
|
|
+ bflb_gpio_set_reg(pctl, data->hwirq, REG_GPIOx_INT_CLR,
|
|
+ FIELD_PREP(REG_GPIOx_INT_CLR, 1));
|
|
+
|
|
+ bflb_gpio_set_reg(pctl, data->hwirq, REG_GPIOx_INT_CLR,
|
|
+ FIELD_PREP(REG_GPIOx_INT_CLR, 0));
|
|
+
|
|
+ bflb_gpio_irq_unmask(data);
|
|
+
|
|
+ dev_dbg(pctl->dev, "Pin %lu IRQ Started", data->hwirq);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+//AH: Set the specified GPIO's interrupt mode
|
|
+static int bflb_gpio_irq_set_type(struct irq_data *data, unsigned int type)
|
|
+{
|
|
+ struct bflb_gpio_pinctrl *pctl =
|
|
+ gpiochip_get_data(irq_data_get_irq_chip_data(data));
|
|
+
|
|
+ unsigned int irqtype = bflb_gpio_irq_type(type);
|
|
+
|
|
+ if (irqtype == 0)
|
|
+ return -EINVAL;
|
|
+
|
|
+ bflb_gpio_set_reg(pctl, data->hwirq, REG_GPIOx_INT_MODE_SET,
|
|
+ FIELD_PREP(REG_GPIOx_INT_MODE_SET, irqtype));
|
|
+
|
|
+ if (type & IRQ_TYPE_LEVEL_MASK)
|
|
+ irq_set_handler_locked(data, handle_level_irq);
|
|
+ else
|
|
+ irq_set_handler_locked(data, handle_edge_irq);
|
|
+
|
|
+ dev_dbg(pctl->dev, "Pin %lu IRQ type set to %u", data->hwirq, irqtype);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+//AH: Handle GPIO interrupts on this controller
|
|
+static void bflb_gpio_irq_handler(struct irq_desc *desc)
|
|
+{
|
|
+ struct irq_chip *chip = irq_desc_get_chip(desc);
|
|
+ u8 *grpp = irq_desc_get_handler_data(desc);
|
|
+ struct bflb_gpio_pinctrl *pctl;
|
|
+ unsigned int pinh;
|
|
+ unsigned long reg;
|
|
+ struct gpio_chip *gc;
|
|
+
|
|
+ pctl = container_of(grpp - *grpp, typeof(*pctl), irqgrps[0]);
|
|
+ gc = &pctl->gpio_chip;
|
|
+
|
|
+ chained_irq_enter(chip, desc);
|
|
+
|
|
+ //We must go through each individual GPIO register to read its interrupt
|
|
+ //status. There is no gpio_cfg128+ helper register for interrupts
|
|
+ //(looking at BL808 RM)
|
|
+ for (pinh = 0; pinh < gc->ngpio; pinh += 1) {
|
|
+ if (test_bit(pinh, pctl->irqsunmasked)) {
|
|
+ dev_dbg(pctl->dev, "Reading IRQ status of pin %u", pinh);
|
|
+
|
|
+ reg = readl_relaxed(pctl->base + REG_GPIO(pinh));
|
|
+
|
|
+ if (reg & REG_GPIOx_INT_STAT) {
|
|
+ generic_handle_domain_irq(gc->irq.domain, pinh);
|
|
+ dev_dbg(pctl->dev, "Pin %u IRQ Fire", pinh);
|
|
+ }
|
|
+ } else {
|
|
+ dev_dbg(pctl->dev, "Ignoring IRQ status of masked pin %u", pinh);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ chained_irq_exit(chip, desc);
|
|
+}
|
|
+
|
|
+static const struct irq_chip bflb_gpio_irqchip = {
|
|
+ .name = "bflb-gpio",
|
|
+ .irq_startup = bflb_gpio_irq_startup,
|
|
+ .irq_ack = bflb_gpio_irq_ack,
|
|
+ .irq_mask = bflb_gpio_irq_mask,
|
|
+ .irq_unmask = bflb_gpio_irq_unmask,
|
|
+ .irq_set_type = bflb_gpio_irq_set_type,
|
|
+ .flags = IRQCHIP_IMMUTABLE,
|
|
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
|
|
+};
|
|
+
|
|
+static int bflb_gpio_request(struct gpio_chip *chip, unsigned int offset)
|
|
+{
|
|
+ int ret;
|
|
+ struct bflb_gpio_pinctrl *pctl = gpiochip_get_data(chip);
|
|
+
|
|
+ ret = pinctrl_gpio_request(chip->base + offset);
|
|
+
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ bflb_gpio_set_reg(pctl, offset, REG_GPIOx_FUNC_SEL,
|
|
+ FIELD_PREP(REG_GPIOx_FUNC_SEL, 11/*SWGPIO*/));
|
|
+
|
|
+ dev_dbg(pctl->dev, "Pin %u set to function GPIO as part of request",
|
|
+ offset);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Probe & register */
|
|
+
|
|
+static int bflb_gpio_register(struct bflb_gpio_pinctrl *pctl)
|
|
+{
|
|
+ struct gpio_irq_chip *girq = &pctl->gpio_chip.irq;
|
|
+ void **irq_data = NULL;
|
|
+ int ret;
|
|
+
|
|
+ pctl->gpio_chip.label = dev_name(pctl->dev);
|
|
+ pctl->gpio_chip.request = bflb_gpio_request;
|
|
+ pctl->gpio_chip.free = gpiochip_generic_free;
|
|
+ pctl->gpio_chip.get_direction = bflb_gpio_get_direction;
|
|
+ pctl->gpio_chip.direction_input = bflb_gpio_direction_input;
|
|
+ pctl->gpio_chip.direction_output = bflb_gpio_direction_output;
|
|
+ pctl->gpio_chip.get = bflb_gpio_get;
|
|
+ pctl->gpio_chip.set = bflb_gpio_set;
|
|
+ pctl->gpio_chip.set_config = bflb_gpio_set_config;
|
|
+ pctl->gpio_chip.base = -1;
|
|
+ pctl->gpio_chip.ngpio = pctl->pinctrl_desc.npins;
|
|
+ pctl->gpio_chip.parent = pctl->dev;
|
|
+
|
|
+ if (girq->num_parents) {
|
|
+ int i;
|
|
+
|
|
+ gpio_irq_chip_set_chip(girq, &bflb_gpio_irqchip);
|
|
+
|
|
+ girq->parent_handler = bflb_gpio_irq_handler;
|
|
+
|
|
+ girq->parents = kmalloc_array(girq->num_parents, sizeof(*girq->parents),
|
|
+ GFP_KERNEL);
|
|
+ irq_data = kmalloc_array(girq->num_parents, sizeof(*irq_data),
|
|
+ GFP_KERNEL);
|
|
+
|
|
+ if (!girq->parents || !irq_data) {
|
|
+ ret = -ENOMEM;
|
|
+ goto out_free_irq_data;
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < girq->num_parents; i++) {
|
|
+ ret = platform_get_irq(to_platform_device(pctl->dev), i);
|
|
+
|
|
+ if (ret < 0)
|
|
+ goto out_free_irq_data;
|
|
+
|
|
+ girq->parents[i] = ret;
|
|
+ pctl->irqgrps[i] = i;
|
|
+ irq_data[i] = &pctl->irqgrps[i];
|
|
+ }
|
|
+
|
|
+ girq->parent_handler_data_array = irq_data;
|
|
+ girq->per_parent_data = true;
|
|
+ girq->default_type = IRQ_TYPE_NONE;
|
|
+ girq->handler = handle_level_irq;
|
|
+ }
|
|
+
|
|
+ ret = devm_gpiochip_add_data(pctl->dev, &pctl->gpio_chip, pctl);
|
|
+
|
|
+out_free_irq_data:
|
|
+ kfree(girq->parents);
|
|
+ kfree(irq_data);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int bflb_gpio_pinctrl_probe(struct platform_device *pdev)
|
|
+{
|
|
+ struct bflb_gpio_pinctrl *pctl;
|
|
+ struct pinctrl_pin_desc *pins;
|
|
+
|
|
+ unsigned int npins;
|
|
+ const char **pin_names;
|
|
+ unsigned int *pin_nums;
|
|
+ unsigned int i, nirqs = 0;
|
|
+ int res;
|
|
+
|
|
+ if (of_property_read_bool(pdev->dev.of_node, "interrupt-controller")) {
|
|
+ res = platform_irq_count(pdev);
|
|
+ if (res > 0)
|
|
+ nirqs = res;
|
|
+ }
|
|
+
|
|
+ pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL);
|
|
+
|
|
+ if (!pctl)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ pctl->dev = &pdev->dev;
|
|
+ pctl->gpio_chip.irq.num_parents = nirqs;
|
|
+
|
|
+ dev_set_drvdata(&pdev->dev, pctl);
|
|
+
|
|
+ if (of_property_read_u32(pdev->dev.of_node, "bflb,npins", &npins))
|
|
+ return dev_err_probe(&pdev->dev, -EINVAL,
|
|
+ "bflb,npins property not found\n");
|
|
+
|
|
+ pctl->irqsunmasked = devm_bitmap_zalloc(&pdev->dev, npins, GFP_KERNEL);
|
|
+
|
|
+ pins = devm_kmalloc_array(&pdev->dev, npins, sizeof(pins[0]), GFP_KERNEL);
|
|
+ pin_names = devm_kmalloc_array(&pdev->dev, npins, sizeof(pin_names[0]),
|
|
+ GFP_KERNEL);
|
|
+ pin_nums = devm_kmalloc_array(&pdev->dev, npins, sizeof(pin_nums[0]),
|
|
+ GFP_KERNEL);
|
|
+
|
|
+ if (!pins || !pin_names || !pin_nums)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ pctl->base = devm_platform_ioremap_resource(pdev, 0);
|
|
+
|
|
+ if (IS_ERR(pctl->base))
|
|
+ return PTR_ERR(pctl->base);
|
|
+
|
|
+ pctl->map = devm_regmap_init_mmio(&pdev->dev, pctl->base, ®map_config);
|
|
+
|
|
+ if (IS_ERR(pctl->map))
|
|
+ return dev_err_probe(&pdev->dev, PTR_ERR(pctl->map),
|
|
+ "Failed to create regmap\n");
|
|
+
|
|
+ for (i = 0; i < npins; i++) {
|
|
+ pins[i].number = i;
|
|
+ pins[i].name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "GPIO%u", i);
|
|
+ pins[i].drv_data = pctl;
|
|
+ pin_names[i] = pins[i].name;
|
|
+ pin_nums[i] = i;
|
|
+ }
|
|
+
|
|
+ pctl->pinctrl_desc.name = dev_name(pctl->dev);
|
|
+ pctl->pinctrl_desc.pins = pins;
|
|
+ pctl->pinctrl_desc.npins = npins;
|
|
+ pctl->pinctrl_desc.pctlops = &bflb_gpio_pinctrl_ops;
|
|
+ pctl->pinctrl_desc.pmxops = &bflb_gpio_pinmux_ops;
|
|
+
|
|
+ pctl->pctldev = devm_pinctrl_register(&pdev->dev, &pctl->pinctrl_desc,
|
|
+ pctl);
|
|
+
|
|
+ if (IS_ERR(pctl->pctldev))
|
|
+ return dev_err_probe(&pdev->dev, PTR_ERR(pctl->pctldev),
|
|
+ "Failed to register pinctrl device.\n");
|
|
+
|
|
+ for (i = 0; i < npins; i++) {
|
|
+ res = pinctrl_generic_add_group(pctl->pctldev,
|
|
+ pins[i].name, pin_nums + i, 1, pctl);
|
|
+
|
|
+ dev_dbg(&pdev->dev, "Registered pin %s with numeric %u",
|
|
+ pins[i].name, i);
|
|
+
|
|
+ if (res < 0)
|
|
+ return dev_err_probe(pctl->dev, res, "Failed to register group");
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < ARRAY_SIZE(pinmux_functions); ++i) {
|
|
+ if (pinmux_functions[i]) {
|
|
+ res = pinmux_generic_add_function(pctl->pctldev,
|
|
+ pinmux_functions[i], pin_names, npins, pctl);
|
|
+
|
|
+ dev_dbg(&pdev->dev, "Registered function %s with numeric %u",
|
|
+ pinmux_functions[i], i);
|
|
+
|
|
+ if (res < 0)
|
|
+ return dev_err_probe(pctl->dev, res,
|
|
+ "Failed to register function.");
|
|
+ }
|
|
+ }
|
|
+
|
|
+ dev_info(&pdev->dev, "Bouffalo Lab pinctrl+GPIO(+interrupt) controller - "
|
|
+ "Registered %lu function(s) for %u pin(s)",
|
|
+
|
|
+ ARRAY_SIZE(pinmux_functions), npins);
|
|
+
|
|
+ return bflb_gpio_register(pctl);
|
|
+}
|
|
+
|
|
+static const struct of_device_id bflb_gpio_pinctrl_of_match[] = {
|
|
+ { .compatible = "bflb,pinctrl", },
|
|
+ { }
|
|
+};
|
|
+
|
|
+MODULE_DEVICE_TABLE(of, bflb_gpio_pinctrl_of_match);
|
|
+
|
|
+static struct platform_driver bflb_gpio_pinctrl_driver = {
|
|
+ .driver = {
|
|
+ .name = "bflb-gpio-pinctrl",
|
|
+ .of_match_table = bflb_gpio_pinctrl_of_match,
|
|
+ .suppress_bind_attrs = true,
|
|
+ },
|
|
+ .probe = bflb_gpio_pinctrl_probe,
|
|
+};
|
|
+
|
|
+module_platform_driver(bflb_gpio_pinctrl_driver);
|
|
+
|
|
+MODULE_DESCRIPTION("Bouffalo BL808 pinctrl/GPIO driver");
|
|
+MODULE_AUTHOR("Alexander Horner <contact@alexhorner.cc>");
|
|
+MODULE_LICENSE("GPL v2");
|
|
diff --git a/include/dt-bindings/mailbox/bflb-ipc.h b/include/dt-bindings/mailbox/bflb-ipc.h
|
|
index 0a3c6745a673..9763460edbcc 100644
|
|
--- a/include/dt-bindings/mailbox/bflb-ipc.h
|
|
+++ b/include/dt-bindings/mailbox/bflb-ipc.h
|
|
@@ -13,5 +13,8 @@
|
|
/* Peripheral device ID */
|
|
#define BFLB_IPC_DEVICE_SDHCI 0
|
|
#define BFLB_IPC_DEVICE_UART2 1
|
|
+#define BFLB_IPC_DEVICE_USB 2
|
|
+#define BFLB_IPC_DEVICE_EMAC 3
|
|
+#define BFLB_IPC_DEVICE_GPIO 4
|
|
|
|
#endif
|
|
--
|
|
2.25.1
|
|
|