diff --git a/boards/intel/btl/intel_btl_s_crb.dts b/boards/intel/btl/intel_btl_s_crb.dts index 3ae2d4592c8df..fb526ca62590c 100644 --- a/boards/intel/btl/intel_btl_s_crb.dts +++ b/boards/intel/btl/intel_btl_s_crb.dts @@ -31,6 +31,10 @@ status = "okay"; }; +&mfd { + status = "okay"; +}; + &rtc { status = "okay"; }; diff --git a/drivers/bbram/CMakeLists.txt b/drivers/bbram/CMakeLists.txt index 87a41054ce8a8..37fca4ef63da4 100644 --- a/drivers/bbram/CMakeLists.txt +++ b/drivers/bbram/CMakeLists.txt @@ -18,3 +18,4 @@ zephyr_library_sources_ifdef(CONFIG_BBRAM_MICROCHIP_MCP7940N_EMUL bbram_microchi zephyr_library_sources_ifdef(CONFIG_BBRAM_XEC bbram_xec.c) zephyr_library_sources_ifdef(CONFIG_BBRAM_STM32 bbram_stm32.c) zephyr_library_sources_ifdef(CONFIG_BBRAM_RTS5912 bbram_rts5912.c) +zephyr_library_sources_ifdef(CONFIG_BBRAM_MOTOROLA_MC146818 bbram_mc146818.c) diff --git a/drivers/bbram/Kconfig b/drivers/bbram/Kconfig index 5c2bb6bc4a1d6..530312bd294ce 100644 --- a/drivers/bbram/Kconfig +++ b/drivers/bbram/Kconfig @@ -44,4 +44,6 @@ source "drivers/bbram/Kconfig.stm32" source "drivers/bbram/Kconfig.rts5912" +source "drivers/bbram/Kconfig.mc146818" + endif # BBRAM diff --git a/drivers/bbram/Kconfig.mc146818 b/drivers/bbram/Kconfig.mc146818 new file mode 100644 index 0000000000000..eb67c85975017 --- /dev/null +++ b/drivers/bbram/Kconfig.mc146818 @@ -0,0 +1,12 @@ +# Intel SoC BBRAM configuration options + +# Copyright (c) 2025 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +config BBRAM_MOTOROLA_MC146818 + bool "BBRAM driver for x86 CMOS/RTC clock's bbram" + default y if !COUNTER + select MFD + depends on DT_HAS_MOTOROLA_MC146818_BBRAM_ENABLED + help + Enable driver for Motorola mc146818 BBRAM. diff --git a/drivers/bbram/bbram_mc146818.c b/drivers/bbram/bbram_mc146818.c new file mode 100644 index 0000000000000..37b35feb2ccf5 --- /dev/null +++ b/drivers/bbram/bbram_mc146818.c @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2025 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Read and Write access to offset ranges 0x2A(42)-0x31(49) and 0xAA(170)-0xB1(177) + * are lockable through BIOS setting. To access the memory in those offsets, + * disable the Lock in BIOS through following steps. + * Intel Advanced Menu -> PCH-IO Configuration -> Security Configuration -> + * RTC Memory Lock -> Disable + */ + +#define DT_DRV_COMPAT motorola_mc146818_bbram + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MIN_SIZE 1 /* Minimum size to write */ +#define MIN_OFFSET 0x0E /* Starting offset of memory */ +#define MAX_STD 0x7F /* Last offset of Standard memory bank */ +#define RTC_CENT 0x32 /* Offset for RTC Century Byte */ + +struct bbram_mc146818_config { + const struct device *mfd; + size_t mem_size; +}; + +struct bbram_mc146818_data { + struct k_spinlock lock; +}; + +static int bbram_mc146818_read(const struct device *dev, size_t offset, + size_t size, uint8_t *data) +{ + const struct bbram_mc146818_config *config = dev->config; + struct bbram_mc146818_data *dev_data = dev->data; + + if (size < MIN_SIZE || offset + size > config->mem_size + || data == NULL) { + return -EFAULT; + } + + offset += MIN_OFFSET; + + k_spinlock_key_t key = k_spin_lock(&dev_data->lock); + + for (size_t i = 0; i < size; i++) { + if (offset < MAX_STD) { + if (offset >= RTC_CENT) { + + /* RTC_CENT byte is used to store Century data for the + * RTC time and date, so skipping read/write operation + * to this byte. + */ + + *(data + i) = mfd_mc146818_std_read(config->mfd, offset+1); + } else { + *(data + i) = mfd_mc146818_std_read(config->mfd, offset); + } + } else { + *(data + i) = mfd_mc146818_ext_read(config->mfd, offset+1); + } + offset++; + } + + k_spin_unlock(&dev_data->lock, key); + return 0; +} + +static int bbram_mc146818_write(const struct device *dev, size_t offset, + size_t size, const uint8_t *data) +{ + const struct bbram_mc146818_config *config = dev->config; + struct bbram_mc146818_data *dev_data = dev->data; + + if (size < MIN_SIZE || offset + size > config->mem_size + || data == NULL) { + return -EFAULT; + } + + offset += MIN_OFFSET; + + k_spinlock_key_t key = k_spin_lock(&dev_data->lock); + + for (size_t i = 0; i < size; i++) { + if (offset < MAX_STD) { + if (offset >= RTC_CENT) { + + /* RTC_CENT byte is used to store Century data for the + * RTC time and date, so skipping read/write operation + * to this byte. + */ + + mfd_mc146818_std_write(config->mfd, offset+1, *(data + i)); + } else { + mfd_mc146818_std_write(config->mfd, offset, *(data + i)); + } + } else { + mfd_mc146818_ext_write(config->mfd, offset+1, *(data + i)); + } + offset++; + } + + k_spin_unlock(&dev_data->lock, key); + return 0; +} + +static int bbram_mc146818_get_size(const struct device *dev, size_t *size) +{ + const struct bbram_mc146818_config *config = dev->config; + + *size = config->mem_size; + + return 0; +} + +static const struct bbram_driver_api bbram_mc146818_api = { + .read = bbram_mc146818_read, + .write = bbram_mc146818_write, + .get_size = bbram_mc146818_get_size, +}; + +static int bbram_mc146818_init(const struct device *dev) +{ + const struct bbram_mc146818_config *config = dev->config; + + if (!device_is_ready(config->mfd)) { + return -ENODEV; + } + + return 0; +} + +#define BBRAM_MC146818_DEV_CFG(n) \ + static const struct bbram_mc146818_config bbram_config_##n = { \ + .mfd = DEVICE_DT_GET(DT_INST_PARENT(n)), \ + .mem_size = DT_INST_PROP(n, size), \ + }; \ + static struct bbram_mc146818_data bbram_data_##n; \ + DEVICE_DT_INST_DEFINE(n, &bbram_mc146818_init, NULL, \ + &bbram_data_##n, &bbram_config_##n, \ + POST_KERNEL, \ + UTIL_INC(CONFIG_MFD_MOTOROLA_MC146818_INIT_PRIORITY), \ + &bbram_mc146818_api); \ + +DT_INST_FOREACH_STATUS_OKAY(BBRAM_MC146818_DEV_CFG) diff --git a/drivers/counter/Kconfig.cmos b/drivers/counter/Kconfig.cmos index 1e9de0b3a5793..63aa9938fe991 100644 --- a/drivers/counter/Kconfig.cmos +++ b/drivers/counter/Kconfig.cmos @@ -6,4 +6,5 @@ config COUNTER_CMOS bool "Counter driver for x86 CMOS/RTC clock" default y if !RTC + select MFD depends on DT_HAS_MOTOROLA_MC146818_ENABLED diff --git a/drivers/counter/counter_cmos.c b/drivers/counter/counter_cmos.c index 2fbbf7efdcf6b..b48349f818e86 100644 --- a/drivers/counter/counter_cmos.c +++ b/drivers/counter/counter_cmos.c @@ -19,8 +19,8 @@ /* The "CMOS" device is accessed via an address latch and data port. */ -#define X86_CMOS_ADDR (DT_INST_REG_ADDR_BY_IDX(0, 0)) -#define X86_CMOS_DATA (DT_INST_REG_ADDR_BY_IDX(0, 1)) +#define X86_CMOS_ADDR (DT_REG_ADDR_BY_IDX(DT_INST_PARENT(0), 0)) +#define X86_CMOS_DATA (DT_REG_ADDR_BY_IDX(DT_INST_PARENT(0), 1)) /* * A snapshot of the RTC state, or at least the state we're @@ -204,4 +204,5 @@ static DEVICE_API(counter, api) = { }; DEVICE_DT_INST_DEFINE(0, NULL, NULL, NULL, &info, POST_KERNEL, - CONFIG_COUNTER_INIT_PRIORITY, &api); + UTIL_INC(CONFIG_MFD_MOTOROLA_MC146818_INIT_PRIORITY), + &api); diff --git a/drivers/mfd/CMakeLists.txt b/drivers/mfd/CMakeLists.txt index 3c477fc7da861..fbe364e6ccb16 100644 --- a/drivers/mfd/CMakeLists.txt +++ b/drivers/mfd/CMakeLists.txt @@ -25,3 +25,4 @@ zephyr_library_sources_ifdef(CONFIG_MFD_DS3231 mfd_ds3231.c) zephyr_library_sources_ifdef(CONFIG_MFD_MAX22017 mfd_max22017.c) zephyr_library_sources_ifdef(CONFIG_MFD_MCHP_SAM_FLEXCOM mfd_mchp_sam_flexcom.c) zephyr_library_sources_ifdef(CONFIG_MFD_PF1550 mfd_pf1550.c) +zephyr_library_sources_ifdef(CONFIG_MFD_MOTOROLA_MC146818 mfd_mc146818.c) diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 86a11a72b410b..c76add25cd10a 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -37,5 +37,6 @@ source "drivers/mfd/Kconfig.pf1550" source "drivers/mfd/Kconfig.lpflexcomm" source "drivers/mfd/Kconfig.tle9104" source "drivers/mfd/Kconfig.it8801" +source "drivers/mfd/Kconfig.mc146818" endif # MFD diff --git a/drivers/mfd/Kconfig.mc146818 b/drivers/mfd/Kconfig.mc146818 new file mode 100644 index 0000000000000..289b3434c7849 --- /dev/null +++ b/drivers/mfd/Kconfig.mc146818 @@ -0,0 +1,20 @@ +# Intel SoC RTC configuration options + +# Copyright (c) 2025 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +config MFD_MOTOROLA_MC146818 + bool "MOTOROLA MC146818 multi-function device driver" + default y + depends on DT_HAS_MOTOROLA_MC146818_MFD_ENABLED + help + common code required by bbram and rtc, which will likely be a locking mechanism + so both RTC and BBRAM can set/get regs safely and independently. + +config MFD_MOTOROLA_MC146818_INIT_PRIORITY + int "Init priority of mc146818 MFD" + depends on MFD_MOTOROLA_MC146818 + default 50 + help + Initialization priority for the MOTOROLA MC146818 MFD driver. + It must be greater than RTC, COUNTER and BBRAM driver init priority. diff --git a/drivers/mfd/mfd_mc146818.c b/drivers/mfd/mfd_mc146818.c new file mode 100644 index 0000000000000..835d440d1b3af --- /dev/null +++ b/drivers/mfd/mfd_mc146818.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2025 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT motorola_mc146818_mfd + +#include +#include +#include +#include +#include +#include +#include +#include + +#define RTC_STD_INDEX (DT_INST_REG_ADDR_BY_IDX(0, 0)) +#define RTC_STD_TARGET (DT_INST_REG_ADDR_BY_IDX(0, 1)) +#define RTC_EXT_INDEX (DT_INST_REG_ADDR_BY_IDX(0, 2)) +#define RTC_EXT_TARGET (DT_INST_REG_ADDR_BY_IDX(0, 3)) + +struct mfd_mc146818_data { + struct k_spinlock lock; +}; + +uint8_t mfd_mc146818_std_read(const struct device *dev, uint8_t offset) +{ + struct mfd_mc146818_data *data = dev->data; + uint8_t value; + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + sys_out8(offset, RTC_STD_INDEX); + value = sys_in8(RTC_STD_TARGET); + + k_spin_unlock(&data->lock, key); + return value; +} + +void mfd_mc146818_std_write(const struct device *dev, uint8_t offset, uint8_t value) +{ + struct mfd_mc146818_data *data = dev->data; + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + sys_out8(offset, RTC_STD_INDEX); + sys_out8(value, RTC_STD_TARGET); + + k_spin_unlock(&data->lock, key); +} + +uint8_t mfd_mc146818_ext_read(const struct device *dev, uint8_t offset) +{ + struct mfd_mc146818_data *data = dev->data; + uint8_t value; + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + sys_out8(offset, RTC_EXT_INDEX); + value = sys_in8(RTC_EXT_TARGET); + + k_spin_unlock(&data->lock, key); + return value; +} + +void mfd_mc146818_ext_write(const struct device *dev, uint8_t offset, uint8_t value) +{ + struct mfd_mc146818_data *data = dev->data; + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + sys_out8(offset, RTC_EXT_INDEX); + sys_out8(value, RTC_EXT_TARGET); + + k_spin_unlock(&data->lock, key); +} + +#define MFD_MC146818_DEFINE(inst) \ + static struct mfd_mc146818_data data##inst; \ + DEVICE_DT_INST_DEFINE(inst, NULL, NULL, &data##inst, NULL, \ + POST_KERNEL, \ + CONFIG_MFD_MOTOROLA_MC146818_INIT_PRIORITY, \ + NULL); \ + +DT_INST_FOREACH_STATUS_OKAY(MFD_MC146818_DEFINE) diff --git a/drivers/rtc/Kconfig.mc146818 b/drivers/rtc/Kconfig.mc146818 index 5bf2bfde9a2ce..a71a1fb531169 100644 --- a/drivers/rtc/Kconfig.mc146818 +++ b/drivers/rtc/Kconfig.mc146818 @@ -6,4 +6,5 @@ config RTC_MOTOROLA_MC146818 bool "RTC driver for x86 CMOS/RTC clock" default y if !COUNTER + select MFD depends on DT_HAS_MOTOROLA_MC146818_ENABLED diff --git a/drivers/rtc/rtc_mc146818.c b/drivers/rtc/rtc_mc146818.c index 68069e1a1682a..9c3e2337d89da 100644 --- a/drivers/rtc/rtc_mc146818.c +++ b/drivers/rtc/rtc_mc146818.c @@ -15,9 +15,7 @@ #include #include #include - -#define RTC_STD_INDEX (DT_INST_REG_ADDR_BY_IDX(0, 0)) -#define RTC_STD_TARGET (DT_INST_REG_ADDR_BY_IDX(0, 1)) +#include /* Time indices in RTC RAM */ #define RTC_SEC 0x00 @@ -127,21 +125,9 @@ struct rtc_mc146818_data { void *update_cb_data; }; -static uint8_t rtc_read(int reg) -{ - uint8_t value; - - sys_out8(reg, RTC_STD_INDEX); - value = sys_in8(RTC_STD_TARGET); - - return value; -} - -static void rtc_write(int reg, uint8_t value) -{ - sys_out8(reg, RTC_STD_INDEX); - sys_out8(value, RTC_STD_TARGET); -} +struct rtc_mc146818_config { + const struct device *mfd; +}; static bool rtc_mc146818_validate_time(const struct rtc_time *timeptr) { @@ -172,6 +158,7 @@ static bool rtc_mc146818_validate_time(const struct rtc_time *timeptr) static int rtc_mc146818_set_time(const struct device *dev, const struct rtc_time *timeptr) { struct rtc_mc146818_data * const dev_data = dev->data; + const struct rtc_mc146818_config *config = dev->config; uint8_t value; int year; int cent; @@ -190,23 +177,23 @@ static int rtc_mc146818_set_time(const struct device *dev, const struct rtc_time goto out; } - value = rtc_read(RTC_DATA); - rtc_write(RTC_DATA, value | RTC_UCI_BIT); + value = mfd_mc146818_std_read(config->mfd, RTC_DATA); + mfd_mc146818_std_write(config->mfd, RTC_DATA, value | RTC_UCI_BIT); year = (1900 + timeptr->tm_year) % 100; cent = (1900 + timeptr->tm_year) / 100; - rtc_write(RTC_SEC, (uint8_t)timeptr->tm_sec); - rtc_write(RTC_MIN, (uint8_t)timeptr->tm_min); - rtc_write(RTC_HOUR, (uint8_t)timeptr->tm_hour); - rtc_write(RTC_WDAY, (uint8_t)timeptr->tm_wday); - rtc_write(RTC_MDAY, (uint8_t)timeptr->tm_mday); - rtc_write(RTC_MONTH, (uint8_t)timeptr->tm_mon + 1); - rtc_write(RTC_YEAR, year); - rtc_write(RTC_CENTURY, cent); + mfd_mc146818_std_write(config->mfd, RTC_SEC, (uint8_t)timeptr->tm_sec); + mfd_mc146818_std_write(config->mfd, RTC_MIN, (uint8_t)timeptr->tm_min); + mfd_mc146818_std_write(config->mfd, RTC_HOUR, (uint8_t)timeptr->tm_hour); + mfd_mc146818_std_write(config->mfd, RTC_WDAY, (uint8_t)timeptr->tm_wday); + mfd_mc146818_std_write(config->mfd, RTC_MDAY, (uint8_t)timeptr->tm_mday); + mfd_mc146818_std_write(config->mfd, RTC_MONTH, (uint8_t)timeptr->tm_mon + 1); + mfd_mc146818_std_write(config->mfd, RTC_YEAR, year); + mfd_mc146818_std_write(config->mfd, RTC_CENTURY, cent); value &= (~RTC_UCI_BIT); - rtc_write(RTC_DATA, value); + mfd_mc146818_std_write(config->mfd, RTC_DATA, value); ret = 0; out: k_spin_unlock(&dev_data->lock, key); @@ -216,10 +203,10 @@ static int rtc_mc146818_set_time(const struct device *dev, const struct rtc_time static int rtc_mc146818_get_time(const struct device *dev, struct rtc_time *timeptr) { struct rtc_mc146818_data * const dev_data = dev->data; + const struct rtc_mc146818_config *config = dev->config; int ret; uint8_t cent; uint8_t year; - uint8_t value; k_spinlock_key_t key = k_spin_lock(&dev_data->lock); @@ -229,29 +216,28 @@ static int rtc_mc146818_get_time(const struct device *dev, struct rtc_time *tim goto out; } - if (!(rtc_read(RTC_REG_D) & RTC_VRT_BIT)) { + if (!(mfd_mc146818_std_read(config->mfd, RTC_REG_D) & RTC_VRT_BIT)) { ret = -ENODATA; goto out; } - while (rtc_read(RTC_UIP) & RTC_UIP_BIT) { + while (mfd_mc146818_std_read(config->mfd, RTC_UIP) & RTC_UIP_BIT) { continue; } - cent = rtc_read(RTC_CENTURY); - year = rtc_read(RTC_YEAR); - timeptr->tm_mon = rtc_read(RTC_MONTH) - 1; - timeptr->tm_mday = rtc_read(RTC_MDAY); - timeptr->tm_wday = rtc_read(RTC_WDAY) - 1; - timeptr->tm_hour = rtc_read(RTC_HOUR); - timeptr->tm_min = rtc_read(RTC_MIN); - timeptr->tm_sec = rtc_read(RTC_SEC); + cent = mfd_mc146818_std_read(config->mfd, RTC_CENTURY); + year = mfd_mc146818_std_read(config->mfd, RTC_YEAR); + timeptr->tm_mon = mfd_mc146818_std_read(config->mfd, RTC_MONTH) - 1; + timeptr->tm_mday = mfd_mc146818_std_read(config->mfd, RTC_MDAY); + timeptr->tm_wday = mfd_mc146818_std_read(config->mfd, RTC_WDAY) - 1; + timeptr->tm_hour = mfd_mc146818_std_read(config->mfd, RTC_HOUR); + timeptr->tm_min = mfd_mc146818_std_read(config->mfd, RTC_MIN); + timeptr->tm_sec = mfd_mc146818_std_read(config->mfd, RTC_SEC); timeptr->tm_year = 100 * (int)cent + year - 1900; timeptr->tm_nsec = 0; timeptr->tm_yday = 0; - value = rtc_read(RTC_DATA); /* Check time valid */ if (!rtc_mc146818_validate_time(timeptr)) { @@ -305,6 +291,7 @@ static int rtc_mc146818_alarm_set_time(const struct device *dev, uint16_t id, ui const struct rtc_time *timeptr) { struct rtc_mc146818_data * const dev_data = dev->data; + const struct rtc_mc146818_config *config = dev->config; int ret; k_spinlock_key_t key = k_spin_lock(&dev_data->lock); @@ -326,23 +313,24 @@ static int rtc_mc146818_alarm_set_time(const struct device *dev, uint16_t id, ui } if (mask & RTC_ALARM_TIME_MASK_SECOND) { - rtc_write(RTC_ALARM_SEC, timeptr->tm_sec); + mfd_mc146818_std_write(config->mfd, RTC_ALARM_SEC, timeptr->tm_sec); } else { - rtc_write(RTC_ALARM_SEC, RTC_ALARM_DC); + mfd_mc146818_std_write(config->mfd, RTC_ALARM_SEC, RTC_ALARM_DC); } if (mask & RTC_ALARM_TIME_MASK_MINUTE) { - rtc_write(RTC_ALARM_MIN, timeptr->tm_min); + mfd_mc146818_std_write(config->mfd, RTC_ALARM_MIN, timeptr->tm_min); } else { - rtc_write(RTC_ALARM_SEC, RTC_ALARM_DC); + mfd_mc146818_std_write(config->mfd, RTC_ALARM_SEC, RTC_ALARM_DC); } if (mask & RTC_ALARM_TIME_MASK_HOUR) { - rtc_write(RTC_ALARM_HOUR, timeptr->tm_hour); + mfd_mc146818_std_write(config->mfd, RTC_ALARM_HOUR, timeptr->tm_hour); } else { - rtc_write(RTC_ALARM_SEC, RTC_ALARM_DC); + mfd_mc146818_std_write(config->mfd, RTC_ALARM_SEC, RTC_ALARM_DC); } - rtc_write(RTC_DATA, rtc_read(RTC_DATA) | RTC_AIE_BIT); + mfd_mc146818_std_write(config->mfd, RTC_DATA, + mfd_mc146818_std_read(config->mfd, RTC_DATA) | RTC_AIE_BIT); ret = 0; out: k_spin_unlock(&dev_data->lock, key); @@ -353,6 +341,7 @@ static int rtc_mc146818_alarm_get_time(const struct device *dev, uint16_t id, ui struct rtc_time *timeptr) { struct rtc_mc146818_data * const dev_data = dev->data; + const struct rtc_mc146818_config *config = dev->config; uint8_t value; int ret; @@ -370,19 +359,19 @@ static int rtc_mc146818_alarm_get_time(const struct device *dev, uint16_t id, ui (*mask) = 0; - value = rtc_read(RTC_ALARM_SEC); + value = mfd_mc146818_std_read(config->mfd, RTC_ALARM_SEC); if (value <= MAX_SEC) { timeptr->tm_sec = value; (*mask) |= RTC_ALARM_TIME_MASK_SECOND; } - value = rtc_read(RTC_ALARM_MIN); + value = mfd_mc146818_std_read(config->mfd, RTC_ALARM_MIN); if (value <= MAX_MIN) { timeptr->tm_min = value; (*mask) |= RTC_ALARM_TIME_MASK_MINUTE; } - value = rtc_read(RTC_ALARM_HOUR); + value = mfd_mc146818_std_read(config->mfd, RTC_ALARM_HOUR); if (value <= MAX_HOUR) { timeptr->tm_hour = value; (*mask) |= RTC_ALARM_TIME_MASK_HOUR; @@ -398,6 +387,7 @@ static int rtc_mc146818_alarm_set_callback(const struct device *dev, uint16_t id rtc_alarm_callback callback, void *user_data) { struct rtc_mc146818_data * const dev_data = dev->data; + const struct rtc_mc146818_config *config = dev->config; if (id != 0) { return -EINVAL; @@ -410,10 +400,14 @@ static int rtc_mc146818_alarm_set_callback(const struct device *dev, uint16_t id if (callback != NULL) { /* Enable Alarm callback */ - rtc_write(RTC_DATA, (rtc_read(RTC_DATA) | RTC_AIE_BIT)); + mfd_mc146818_std_write(config->mfd, RTC_DATA, + (mfd_mc146818_std_read(config->mfd, + RTC_DATA) | RTC_AIE_BIT)); } else { /* Disable Alarm callback */ - rtc_write(RTC_DATA, (rtc_read(RTC_DATA) & (~RTC_AIE_BIT))); + mfd_mc146818_std_write(config->mfd, RTC_DATA, + (mfd_mc146818_std_read(config->mfd, + RTC_DATA) & (~RTC_AIE_BIT))); } k_spin_unlock(&dev_data->lock, key); @@ -444,6 +438,7 @@ static int rtc_mc146818_update_set_callback(const struct device *dev, rtc_update_callback callback, void *user_data) { struct rtc_mc146818_data * const dev_data = dev->data; + const struct rtc_mc146818_config *config = dev->config; k_spinlock_key_t key = k_spin_lock(&dev_data->lock); @@ -452,10 +447,14 @@ static int rtc_mc146818_update_set_callback(const struct device *dev, if (callback != NULL) { /* Enable update callback */ - rtc_write(RTC_DATA, (rtc_read(RTC_DATA) | RTC_UIE_BIT)); + mfd_mc146818_std_write(config->mfd, RTC_DATA, + (mfd_mc146818_std_read(config->mfd, + RTC_DATA) | RTC_UIE_BIT)); } else { /* Disable update callback */ - rtc_write(RTC_DATA, (rtc_read(RTC_DATA) & (~RTC_UIE_BIT))); + mfd_mc146818_std_write(config->mfd, RTC_DATA, + (mfd_mc146818_std_read(config->mfd, + RTC_DATA) & (~RTC_UIE_BIT))); } @@ -468,12 +467,13 @@ static int rtc_mc146818_update_set_callback(const struct device *dev, static void rtc_mc146818_isr(const struct device *dev) { struct rtc_mc146818_data * const dev_data = dev->data; + const struct rtc_mc146818_config *config = dev->config; uint8_t regc; ARG_UNUSED(dev_data); /* Read register, which clears the register */ - regc = rtc_read(RTC_FLAG); + regc = mfd_mc146818_std_read(config->mfd, RTC_FLAG); #if defined(CONFIG_RTC_ALARM) if (regc & RTC_AF_BIT) { @@ -514,11 +514,17 @@ static DEVICE_API(rtc, rtc_mc146818_driver_api) = { #define RTC_MC146818_INIT_FN_DEFINE(n) \ static int rtc_mc146818_init##n(const struct device *dev) \ { \ - rtc_write(RTC_REG_A, \ + const struct rtc_mc146818_config *config = dev->config; \ + \ + if (!device_is_ready(config->mfd)) { \ + return -ENODEV; \ + } \ + mfd_mc146818_std_write(config->mfd, RTC_REG_A, \ _CONCAT(RTC_IN_CLK_DIV_BITS_, \ DT_INST_PROP(n, clock_frequency))); \ \ - rtc_write(RTC_REG_B, RTC_DMODE_BIT | RTC_HFORMAT_BIT); \ + mfd_mc146818_std_write(config->mfd, \ + RTC_REG_B, RTC_DMODE_BIT | RTC_HFORMAT_BIT); \ \ IRQ_CONNECT(DT_INST_IRQN(0), \ DT_INST_IRQ(0, priority), \ @@ -530,14 +536,17 @@ static DEVICE_API(rtc, rtc_mc146818_driver_api) = { return 0; \ } -#define RTC_MC146818_DEV_CFG(inst) \ - struct rtc_mc146818_data rtc_mc146818_data##inst; \ - \ - RTC_MC146818_INIT_FN_DEFINE(inst) \ - \ - DEVICE_DT_INST_DEFINE(inst, &rtc_mc146818_init##inst, NULL, \ - &rtc_mc146818_data##inst, NULL, POST_KERNEL, \ - CONFIG_RTC_INIT_PRIORITY, \ - &rtc_mc146818_driver_api); \ +#define RTC_MC146818_DEV_CFG(inst) \ + static struct rtc_mc146818_data rtc_mc146818_data##inst; \ + \ + static const struct rtc_mc146818_config rtc_mc146818_config##inst = { \ + .mfd = DEVICE_DT_GET(DT_INST_PARENT(inst))}; \ + \ + RTC_MC146818_INIT_FN_DEFINE(inst) \ + DEVICE_DT_INST_DEFINE(inst, &rtc_mc146818_init##inst, NULL, \ + &rtc_mc146818_data##inst, &rtc_mc146818_config##inst,\ + POST_KERNEL, \ + UTIL_INC(CONFIG_MFD_MOTOROLA_MC146818_INIT_PRIORITY),\ + &rtc_mc146818_driver_api); \ DT_INST_FOREACH_STATUS_OKAY(RTC_MC146818_DEV_CFG) diff --git a/dts/bindings/memory-controllers/motorola,mc146818-bbram.yaml b/dts/bindings/memory-controllers/motorola,mc146818-bbram.yaml new file mode 100644 index 0000000000000..b57f9c77b39e7 --- /dev/null +++ b/dts/bindings/memory-controllers/motorola,mc146818-bbram.yaml @@ -0,0 +1,17 @@ +# Copyright (c) 2025, Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +description: Motorola MC146818 compatible Real Timer Clock Battery Backed RAM + +compatible: "motorola,mc146818-bbram" + +include: base.yaml + +on-bus: mc146818-mfd + +properties: + size: + type: int + required: true + description: Memory capacity in bytes. diff --git a/dts/bindings/mfd/motorola,mc146818-mfd.yaml b/dts/bindings/mfd/motorola,mc146818-mfd.yaml new file mode 100644 index 0000000000000..62929d410edeb --- /dev/null +++ b/dts/bindings/mfd/motorola,mc146818-mfd.yaml @@ -0,0 +1,34 @@ +# Copyright (c) 2025, Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +description: | + Motorola MC146818 MFD + + The following example displays the node layout + with every possible partial driver included. + + mfd: mfd@70 { + compatible = "motorola,mc146818-mfd"; + reg = <0x70 0x01 0x71 0x01 0x72 0x01 0x73 0x01>; + rtc: counter: rtc { + compatible = "motorola,mc146818"; + interrupts = <8 IRQ_TYPE_LOWEST_EDGE_RISING 3>; + interrupt-parent = <&intc>; + alarms-count = <1>; + + status = "okay"; + }; + + bbram: bbram { + compatible = "motorola,mc146818-bbram"; + size = <241>; + status = "okay"; + }; + }; + +compatible: "motorola,mc146818-mfd" + +include: base.yaml + +bus: mc146818-mfd diff --git a/dts/bindings/rtc/motorola,mc146818.yaml b/dts/bindings/rtc/motorola,mc146818.yaml index eebb134351e75..1eb1d55d81e7d 100644 --- a/dts/bindings/rtc/motorola,mc146818.yaml +++ b/dts/bindings/rtc/motorola,mc146818.yaml @@ -8,6 +8,8 @@ compatible: "motorola,mc146818" include: [rtc-device.yaml, acpi.yaml] +on-bus: mc146818-mfd + properties: clock-frequency: type: int diff --git a/dts/x86/intel/alder_lake.dtsi b/dts/x86/intel/alder_lake.dtsi index 110cc23872911..bfb7271561fbb 100644 --- a/dts/x86/intel/alder_lake.dtsi +++ b/dts/x86/intel/alder_lake.dtsi @@ -404,12 +404,24 @@ status = "okay"; }; - rtc: counter: rtc@70 { - compatible = "motorola,mc146818"; - reg = <0x70 0x0D 0x71 0x0D>; - interrupts = <8 IRQ_TYPE_LOWEST_EDGE_RISING 3>; - interrupt-parent = <&intc>; - alarms-count = <1>; + mfd: mfd@70 { + compatible = "motorola,mc146818-mfd"; + reg = <0x70 0x01 0x71 0x01 0x72 0x01 0x73 0x01>; + + rtc: counter: rtc { + compatible = "motorola,mc146818"; + interrupts = <8 IRQ_TYPE_LOWEST_EDGE_RISING 3>; + interrupt-parent = <&intc>; + alarms-count = <1>; + + status = "okay"; + }; + + bbram: bbram { + compatible = "motorola,mc146818-bbram"; + size = <241>; + status = "okay"; + }; status = "okay"; }; diff --git a/dts/x86/intel/apollo_lake.dtsi b/dts/x86/intel/apollo_lake.dtsi index 5920decfc4d9e..882f94ec8af9a 100644 --- a/dts/x86/intel/apollo_lake.dtsi +++ b/dts/x86/intel/apollo_lake.dtsi @@ -389,15 +389,22 @@ status = "okay"; }; - rtc: counter: rtc@70 { - compatible = "motorola,mc146818"; - reg = <0x70 0x0D 0x71 0x0D>; - interrupts = <8 IRQ_TYPE_LOWEST_EDGE_RISING 3>; - interrupt-parent = <&intc>; - alarms-count = <1>; + mfd: mfd@70 { + compatible = "motorola,mc146818-mfd"; + reg = <0x70 0x01 0x71 0x01 0x72 0x01 0x73 0x01>; + + rtc: counter: rtc { + compatible = "motorola,mc146818"; + interrupts = <8 IRQ_TYPE_LOWEST_EDGE_RISING 3>; + interrupt-parent = <&intc>; + alarms-count = <1>; + + status = "okay"; + }; status = "okay"; }; + }; gpio_n: gpio-north { diff --git a/dts/x86/intel/atom.dtsi b/dts/x86/intel/atom.dtsi index d1d4758c3cd5a..fc91abb7e5e02 100644 --- a/dts/x86/intel/atom.dtsi +++ b/dts/x86/intel/atom.dtsi @@ -78,15 +78,20 @@ status = "disabled"; }; - rtc: counter: rtc@70 { - compatible = "motorola,mc146818"; - reg = <0x70 0x0D 0x71 0x0D>; - interrupts = <8 IRQ_TYPE_LOWEST_EDGE_RISING 3>; - interrupt-parent = <&intc>; - alarms-count = <1>; + mfd: mfd@70 { + compatible = "motorola,mc146818-mfd"; + reg = <0x70 0x01 0x71 0x01 0x72 0x01 0x73 0x01>; + + rtc: counter: rtc { + compatible = "motorola,mc146818"; + interrupts = <8 IRQ_TYPE_LOWEST_EDGE_RISING 3>; + interrupt-parent = <&intc>; + alarms-count = <1>; + + status = "okay"; + }; status = "okay"; }; - }; }; diff --git a/dts/x86/intel/bartlett_lake_s.dtsi b/dts/x86/intel/bartlett_lake_s.dtsi index 70f4df31e28c8..7340c0a142eb9 100644 --- a/dts/x86/intel/bartlett_lake_s.dtsi +++ b/dts/x86/intel/bartlett_lake_s.dtsi @@ -560,12 +560,24 @@ status = "disabled"; }; - rtc: counter: rtc@70 { - compatible = "motorola,mc146818"; - reg = <0x70 0x0D 0x71 0x0D>; - interrupts = <8 IRQ_TYPE_LOWEST_EDGE_RISING 3>; - interrupt-parent = <&intc>; - alarms-count = <1>; + mfd: mfd@70 { + compatible = "motorola,mc146818-mfd"; + reg = <0x70 0x01 0x71 0x01 0x72 0x01 0x73 0x01>; + + rtc: counter: rtc { + compatible = "motorola,mc146818"; + interrupts = <8 IRQ_TYPE_LOWEST_EDGE_RISING 3>; + interrupt-parent = <&intc>; + alarms-count = <1>; + + status = "disabled"; + }; + + bbram: bbram { + compatible = "motorola,mc146818-bbram"; + size = <241>; + status = "disabled"; + }; status = "disabled"; }; diff --git a/dts/x86/intel/elkhart_lake.dtsi b/dts/x86/intel/elkhart_lake.dtsi index 31cfd40496e99..af2cb8b53f769 100644 --- a/dts/x86/intel/elkhart_lake.dtsi +++ b/dts/x86/intel/elkhart_lake.dtsi @@ -710,12 +710,24 @@ status = "disabled"; }; - rtc: counter: rtc@70 { - compatible = "motorola,mc146818"; - reg = <0x70 0x0D 0x71 0x0D>; - interrupts = <8 IRQ_TYPE_LOWEST_EDGE_RISING 3>; - interrupt-parent = <&intc>; - alarms-count = <1>; + mfd: mfd@70 { + compatible = "motorola,mc146818-mfd"; + reg = <0x70 0x01 0x71 0x01 0x72 0x01 0x73 0x01>; + + rtc: counter: rtc { + compatible = "motorola,mc146818"; + interrupts = <8 IRQ_TYPE_LOWEST_EDGE_RISING 3>; + interrupt-parent = <&intc>; + alarms-count = <1>; + + status = "okay"; + }; + + bbram: bbram { + compatible = "motorola,mc146818-bbram"; + size = <241>; + status = "okay"; + }; status = "okay"; }; diff --git a/dts/x86/intel/raptor_lake_p.dtsi b/dts/x86/intel/raptor_lake_p.dtsi index 2f3c4bfa61044..bf450003bab4e 100644 --- a/dts/x86/intel/raptor_lake_p.dtsi +++ b/dts/x86/intel/raptor_lake_p.dtsi @@ -435,12 +435,24 @@ status = "okay"; }; - rtc: counter: rtc@70 { - compatible = "motorola,mc146818"; - reg = <0x70 0x0D 0x71 0x0D>; - interrupts = <8 IRQ_TYPE_LOWEST_EDGE_RISING 3>; - interrupt-parent = <&intc>; - alarms-count = <1>; + mfd: mfd@70 { + compatible = "motorola,mc146818-mfd"; + reg = <0x70 0x01 0x71 0x01 0x72 0x01 0x73 0x01>; + + rtc: counter: rtc { + compatible = "motorola,mc146818"; + interrupts = <8 IRQ_TYPE_LOWEST_EDGE_RISING 3>; + interrupt-parent = <&intc>; + alarms-count = <1>; + + status = "okay"; + }; + + bbram: bbram { + compatible = "motorola,mc146818-bbram"; + size = <241>; + status = "okay"; + }; status = "okay"; }; diff --git a/dts/x86/intel/raptor_lake_s.dtsi b/dts/x86/intel/raptor_lake_s.dtsi index 6c543efb614ce..71b28f47d5eaa 100644 --- a/dts/x86/intel/raptor_lake_s.dtsi +++ b/dts/x86/intel/raptor_lake_s.dtsi @@ -543,12 +543,24 @@ status = "okay"; }; - rtc: counter: rtc@70 { - compatible = "motorola,mc146818"; - reg = <0x70 0x0D 0x71 0x0D>; - interrupts = <8 IRQ_TYPE_LOWEST_EDGE_RISING 3>; - interrupt-parent = <&intc>; - alarms-count = <1>; + mfd: mfd@70 { + compatible = "motorola,mc146818-mfd"; + reg = <0x70 0x01 0x71 0x01 0x72 0x01 0x73 0x01>; + + rtc: counter: rtc { + compatible = "motorola,mc146818"; + interrupts = <8 IRQ_TYPE_LOWEST_EDGE_RISING 3>; + interrupt-parent = <&intc>; + alarms-count = <1>; + + status = "okay"; + }; + + bbram: bbram { + compatible = "motorola,mc146818-bbram"; + size = <241>; + status = "okay"; + }; status = "okay"; }; diff --git a/include/zephyr/drivers/mfd/mc146818.h b/include/zephyr/drivers/mfd/mc146818.h new file mode 100644 index 0000000000000..32dc934b5ec12 --- /dev/null +++ b/include/zephyr/drivers/mfd/mc146818.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2025 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_MFD_MC146818_H_ +#define ZEPHYR_INCLUDE_DRIVERS_MFD_MC146818_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/** + * @brief Read the value at the given offset in standard memory bank. + * + * @param dev mc146818 mfd device + * @param offset memory offset to be read. + * @retval value at the offset + */ +uint8_t mfd_mc146818_std_read(const struct device *dev, uint8_t offset); + +/** + * @brief Write the value at the given offset in standard memory bank. + * + * @param dev mc146818 mfd device + * @param offset memory offset to be written. + * @param value to be written at the offset + */ +void mfd_mc146818_std_write(const struct device *dev, uint8_t offset, uint8_t value); + +/** + * @brief Read the value at the given offset in extended memory bank. + * + * @param dev mc146818 mfd device + * @param offset memory offset to be read. + * @retval value at the offset + */ +uint8_t mfd_mc146818_ext_read(const struct device *dev, uint8_t offset); + +/** + * @brief Write the value at the given offset in extended memory bank. + * + * @param dev mc146818 mfd device + * @param offset memory offset to be written. + * @param value to be written at the offset + */ +void mfd_mc146818_ext_write(const struct device *dev, uint8_t offset, uint8_t value); + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_DRIVERS_MFD_MC146818_H_ */