diff options
Diffstat (limited to 'drivers/rtc/rtc-stm32.c')
| -rw-r--r-- | drivers/rtc/rtc-stm32.c | 78 | 
1 files changed, 78 insertions, 0 deletions
| diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c index 76753c71d92e..98b07969609d 100644 --- a/drivers/rtc/rtc-stm32.c +++ b/drivers/rtc/rtc-stm32.c @@ -5,6 +5,7 @@   */  #include <linux/bcd.h> +#include <linux/bitfield.h>  #include <linux/clk.h>  #include <linux/errno.h>  #include <linux/iopoll.h> @@ -83,6 +84,18 @@  #define STM32_RTC_VERR_MAJREV_SHIFT	4  #define STM32_RTC_VERR_MAJREV		GENMASK(7, 4) +/* STM32_RTC_SECCFGR bit fields */ +#define STM32_RTC_SECCFGR		0x20 +#define STM32_RTC_SECCFGR_ALRA_SEC	BIT(0) +#define STM32_RTC_SECCFGR_INIT_SEC	BIT(14) +#define STM32_RTC_SECCFGR_SEC		BIT(15) + +/* STM32_RTC_RXCIDCFGR bit fields */ +#define STM32_RTC_RXCIDCFGR(x)		(0x80 + 0x4 * (x)) +#define STM32_RTC_RXCIDCFGR_CFEN	BIT(0) +#define STM32_RTC_RXCIDCFGR_CID		GENMASK(6, 4) +#define STM32_RTC_RXCIDCFGR_CID1	1 +  /* STM32_RTC_WPR key constants */  #define RTC_WPR_1ST_KEY			0xCA  #define RTC_WPR_2ND_KEY			0x53 @@ -120,6 +133,7 @@ struct stm32_rtc_data {  	bool has_pclk;  	bool need_dbp;  	bool need_accuracy; +	bool rif_protected;  };  struct stm32_rtc { @@ -134,6 +148,14 @@ struct stm32_rtc {  	int irq_alarm;  }; +struct stm32_rtc_rif_resource { +	unsigned int num; +	u32 bit; +}; + +static const struct stm32_rtc_rif_resource STM32_RTC_RES_ALRA = {0, STM32_RTC_SECCFGR_ALRA_SEC}; +static const struct stm32_rtc_rif_resource STM32_RTC_RES_INIT = {5, STM32_RTC_SECCFGR_INIT_SEC}; +  static void stm32_rtc_wpr_unlock(struct stm32_rtc *rtc)  {  	const struct stm32_rtc_registers *regs = &rtc->data->regs; @@ -553,6 +575,7 @@ static const struct stm32_rtc_data stm32_rtc_data = {  	.has_pclk = false,  	.need_dbp = true,  	.need_accuracy = false, +	.rif_protected = false,  	.regs = {  		.tr = 0x00,  		.dr = 0x04, @@ -575,6 +598,7 @@ static const struct stm32_rtc_data stm32h7_rtc_data = {  	.has_pclk = true,  	.need_dbp = true,  	.need_accuracy = false, +	.rif_protected = false,  	.regs = {  		.tr = 0x00,  		.dr = 0x04, @@ -606,6 +630,7 @@ static const struct stm32_rtc_data stm32mp1_data = {  	.has_pclk = true,  	.need_dbp = false,  	.need_accuracy = true, +	.rif_protected = false,  	.regs = {  		.tr = 0x00,  		.dr = 0x04, @@ -624,14 +649,57 @@ static const struct stm32_rtc_data stm32mp1_data = {  	.clear_events = stm32mp1_rtc_clear_events,  }; +static const struct stm32_rtc_data stm32mp25_data = { +	.has_pclk = true, +	.need_dbp = false, +	.need_accuracy = true, +	.rif_protected = true, +	.regs = { +		.tr = 0x00, +		.dr = 0x04, +		.cr = 0x18, +		.isr = 0x0C, /* named RTC_ICSR on stm32mp25 */ +		.prer = 0x10, +		.alrmar = 0x40, +		.wpr = 0x24, +		.sr = 0x50, +		.scr = 0x5C, +		.verr = 0x3F4, +	}, +	.events = { +		.alra = STM32_RTC_SR_ALRA, +	}, +	.clear_events = stm32mp1_rtc_clear_events, +}; +  static const struct of_device_id stm32_rtc_of_match[] = {  	{ .compatible = "st,stm32-rtc", .data = &stm32_rtc_data },  	{ .compatible = "st,stm32h7-rtc", .data = &stm32h7_rtc_data },  	{ .compatible = "st,stm32mp1-rtc", .data = &stm32mp1_data }, +	{ .compatible = "st,stm32mp25-rtc", .data = &stm32mp25_data },  	{}  };  MODULE_DEVICE_TABLE(of, stm32_rtc_of_match); +static int stm32_rtc_check_rif(struct stm32_rtc *stm32_rtc, +			       struct stm32_rtc_rif_resource res) +{ +	u32 rxcidcfgr = readl_relaxed(stm32_rtc->base + STM32_RTC_RXCIDCFGR(res.num)); +	u32 seccfgr; + +	/* Check if RTC available for our CID */ +	if ((rxcidcfgr & STM32_RTC_RXCIDCFGR_CFEN) && +	    (FIELD_GET(STM32_RTC_RXCIDCFGR_CID, rxcidcfgr) != STM32_RTC_RXCIDCFGR_CID1)) +		return -EACCES; + +	/* Check if RTC available for non secure world */ +	seccfgr = readl_relaxed(stm32_rtc->base + STM32_RTC_SECCFGR); +	if ((seccfgr & STM32_RTC_SECCFGR_SEC) | (seccfgr & res.bit)) +		return -EACCES; + +	return 0; +} +  static int stm32_rtc_init(struct platform_device *pdev,  			  struct stm32_rtc *rtc)  { @@ -787,6 +855,16 @@ static int stm32_rtc_probe(struct platform_device *pdev)  		regmap_update_bits(rtc->dbp, rtc->dbp_reg,  				   rtc->dbp_mask, rtc->dbp_mask); +	if (rtc->data->rif_protected) { +		ret = stm32_rtc_check_rif(rtc, STM32_RTC_RES_INIT); +		if (!ret) +			ret = stm32_rtc_check_rif(rtc, STM32_RTC_RES_ALRA); +		if (ret) { +			dev_err(&pdev->dev, "Failed to probe RTC due to RIF configuration\n"); +			goto err; +		} +	} +  	/*  	 * After a system reset, RTC_ISR.INITS flag can be read to check if  	 * the calendar has been initialized or not. INITS flag is reset by a |