/* * Copyright (c) 2021 IoT.bzh * * SPDX-License-Identifier: Apache-2.0 */ #define DT_DRV_COMPAT renesas_rcar_scif #include #include #include #include #include #include #include #include #include struct uart_rcar_cfg { DEVICE_MMIO_ROM; /* Must be first */ const struct device *clock_dev; struct rcar_cpg_clk mod_clk; struct rcar_cpg_clk bus_clk; const struct pinctrl_dev_config *pcfg; #ifdef CONFIG_UART_INTERRUPT_DRIVEN void (*irq_config_func)(const struct device *dev); #endif bool is_hscif; }; struct uart_rcar_data { DEVICE_MMIO_RAM; /* Must be first */ struct uart_config current_config; uint32_t clk_rate; struct k_spinlock lock; #ifdef CONFIG_UART_INTERRUPT_DRIVEN uart_irq_callback_user_data_t callback; void *cb_data; #endif }; /* Registers */ #define SCSMR 0x00 /* Serial Mode Register */ #define SCBRR 0x04 /* Bit Rate Register */ #define SCSCR 0x08 /* Serial Control Register */ #define SCFTDR 0x0c /* Transmit FIFO Data Register */ #define SCFSR 0x10 /* Serial Status Register */ #define SCFRDR 0x14 /* Receive FIFO Data Register */ #define SCFCR 0x18 /* FIFO Control Register */ #define SCFDR 0x1c /* FIFO Data Count Register */ #define SCSPTR 0x20 /* Serial Port Register */ #define SCLSR 0x24 /* Line Status Register */ #define DL 0x30 /* Frequency Division Register */ #define CKS 0x34 /* Clock Select Register */ #define HSSRR 0x40 /* Sampling Rate Register */ /* SCSMR (Serial Mode Register) */ #define SCSMR_C_A BIT(7) /* Communication Mode */ #define SCSMR_CHR BIT(6) /* 7-bit Character Length */ #define SCSMR_PE BIT(5) /* Parity Enable */ #define SCSMR_O_E BIT(4) /* Odd Parity */ #define SCSMR_STOP BIT(3) /* Stop Bit Length */ #define SCSMR_CKS1 BIT(1) /* Clock Select 1 */ #define SCSMR_CKS0 BIT(0) /* Clock Select 0 */ /* SCSCR (Serial Control Register) */ #define SCSCR_TEIE BIT(11) /* Transmit End Interrupt Enable */ #define SCSCR_TIE BIT(7) /* Transmit Interrupt Enable */ #define SCSCR_RIE BIT(6) /* Receive Interrupt Enable */ #define SCSCR_TE BIT(5) /* Transmit Enable */ #define SCSCR_RE BIT(4) /* Receive Enable */ #define SCSCR_REIE BIT(3) /* Receive Error Interrupt Enable */ #define SCSCR_TOIE BIT(2) /* Timeout Interrupt Enable */ #define SCSCR_CKE1 BIT(1) /* Clock Enable 1 */ #define SCSCR_CKE0 BIT(0) /* Clock Enable 0 */ /* SCFCR (FIFO Control Register) */ #define SCFCR_RTRG1 BIT(7) /* Receive FIFO Data Count Trigger 1 */ #define SCFCR_RTRG0 BIT(6) /* Receive FIFO Data Count Trigger 0 */ #define SCFCR_TTRG1 BIT(5) /* Transmit FIFO Data Count Trigger 1 */ #define SCFCR_TTRG0 BIT(4) /* Transmit FIFO Data Count Trigger 0 */ #define SCFCR_MCE BIT(3) /* Modem Control Enable */ #define SCFCR_TFRST BIT(2) /* Transmit FIFO Data Register Reset */ #define SCFCR_RFRST BIT(1) /* Receive FIFO Data Register Reset */ #define SCFCR_LOOP BIT(0) /* Loopback Test */ /* SCFSR (Serial Status Register) */ #define SCFSR_PER3 BIT(15) /* Parity Error Count 3 */ #define SCFSR_PER2 BIT(14) /* Parity Error Count 2 */ #define SCFSR_PER1 BIT(13) /* Parity Error Count 1 */ #define SCFSR_PER0 BIT(12) /* Parity Error Count 0 */ #define SCFSR_FER3 BIT(11) /* Framing Error Count 3 */ #define SCFSR_FER2 BIT(10) /* Framing Error Count 2 */ #define SCFSR_FER_1 BIT(9) /* Framing Error Count 1 */ #define SCFSR_FER0 BIT(8) /* Framing Error Count 0 */ #define SCFSR_ER BIT(7) /* Receive Error */ #define SCFSR_TEND BIT(6) /* Transmission ended */ #define SCFSR_TDFE BIT(5) /* Transmit FIFO Data Empty */ #define SCFSR_BRK BIT(4) /* Break Detect */ #define SCFSR_FER BIT(3) /* Framing Error */ #define SCFSR_PER BIT(2) /* Parity Error */ #define SCFSR_RDF BIT(1) /* Receive FIFO Data Full */ #define SCFSR_DR BIT(0) /* Receive Data Ready */ /* SCLSR (Line Status Register) on (H)SCIF */ #define SCLSR_TO BIT(2) /* Timeout */ #define SCLSR_ORER BIT(0) /* Overrun Error */ /* HSSRR (Sampling Rate Register) */ #define HSSRR_SRE BIT(15) /* Sampling Rate Register Enable */ #define HSSRR_SRCYC_DEF_VAL 0x7 /* Sampling rate default value */ static uint8_t uart_rcar_read_8(const struct device *dev, uint32_t offs) { return sys_read8(DEVICE_MMIO_GET(dev) + offs); } static void uart_rcar_write_8(const struct device *dev, uint32_t offs, uint8_t value) { sys_write8(value, DEVICE_MMIO_GET(dev) + offs); } static uint16_t uart_rcar_read_16(const struct device *dev, uint32_t offs) { return sys_read16(DEVICE_MMIO_GET(dev) + offs); } static void uart_rcar_write_16(const struct device *dev, uint32_t offs, uint16_t value) { sys_write16(value, DEVICE_MMIO_GET(dev) + offs); } static void uart_rcar_set_baudrate(const struct device *dev, uint32_t baud_rate) { struct uart_rcar_data *data = dev->data; const struct uart_rcar_cfg *cfg = dev->config; uint8_t reg_val; if (cfg->is_hscif) { reg_val = data->clk_rate / (2 * (HSSRR_SRCYC_DEF_VAL + 1) * baud_rate) - 1; } else { reg_val = ((data->clk_rate + 16 * baud_rate) / (32 * baud_rate) - 1); } uart_rcar_write_8(dev, SCBRR, reg_val); } static int uart_rcar_poll_in(const struct device *dev, unsigned char *p_char) { struct uart_rcar_data *data = dev->data; uint16_t reg_val; int ret = 0; k_spinlock_key_t key = k_spin_lock(&data->lock); /* Receive FIFO empty */ if (!((uart_rcar_read_16(dev, SCFSR)) & SCFSR_RDF)) { ret = -1; goto unlock; } *p_char = uart_rcar_read_8(dev, SCFRDR); reg_val = uart_rcar_read_16(dev, SCFSR); reg_val &= ~SCFSR_RDF; uart_rcar_write_16(dev, SCFSR, reg_val); unlock: k_spin_unlock(&data->lock, key); return ret; } static void uart_rcar_poll_out(const struct device *dev, unsigned char out_char) { struct uart_rcar_data *data = dev->data; uint16_t reg_val; k_spinlock_key_t key = k_spin_lock(&data->lock); /* Wait for empty space in transmit FIFO */ while (!(uart_rcar_read_16(dev, SCFSR) & SCFSR_TDFE)) { } uart_rcar_write_8(dev, SCFTDR, out_char); reg_val = uart_rcar_read_16(dev, SCFSR); reg_val &= ~(SCFSR_TDFE | SCFSR_TEND); uart_rcar_write_16(dev, SCFSR, reg_val); k_spin_unlock(&data->lock, key); } static int uart_rcar_configure(const struct device *dev, const struct uart_config *cfg) { struct uart_rcar_data *data = dev->data; const struct uart_rcar_cfg *cfg_drv = dev->config; uint16_t reg_val; k_spinlock_key_t key; if (cfg->parity != UART_CFG_PARITY_NONE || cfg->stop_bits != UART_CFG_STOP_BITS_1 || cfg->data_bits != UART_CFG_DATA_BITS_8 || cfg->flow_ctrl != UART_CFG_FLOW_CTRL_NONE) { return -ENOTSUP; } key = k_spin_lock(&data->lock); /* Disable Transmit and Receive */ reg_val = uart_rcar_read_16(dev, SCSCR); reg_val &= ~(SCSCR_TE | SCSCR_RE); uart_rcar_write_16(dev, SCSCR, reg_val); /* Emptying Transmit and Receive FIFO */ reg_val = uart_rcar_read_16(dev, SCFCR); reg_val |= (SCFCR_TFRST | SCFCR_RFRST); uart_rcar_write_16(dev, SCFCR, reg_val); /* Resetting Errors Registers */ reg_val = uart_rcar_read_16(dev, SCFSR); reg_val &= ~(SCFSR_ER | SCFSR_DR | SCFSR_BRK | SCFSR_RDF); uart_rcar_write_16(dev, SCFSR, reg_val); reg_val = uart_rcar_read_16(dev, SCLSR); reg_val &= ~(SCLSR_TO | SCLSR_ORER); uart_rcar_write_16(dev, SCLSR, reg_val); /* Select internal clock */ reg_val = uart_rcar_read_16(dev, SCSCR); reg_val &= ~(SCSCR_CKE1 | SCSCR_CKE0); uart_rcar_write_16(dev, SCSCR, reg_val); /* Serial Configuration (8N1) & Clock divider selection */ reg_val = uart_rcar_read_16(dev, SCSMR); reg_val &= ~(SCSMR_C_A | SCSMR_CHR | SCSMR_PE | SCSMR_O_E | SCSMR_STOP | SCSMR_CKS1 | SCSMR_CKS0); uart_rcar_write_16(dev, SCSMR, reg_val); if (cfg_drv->is_hscif) { /* TODO: calculate the optimal sampling and bit rates based on error rate */ uart_rcar_write_16(dev, HSSRR, HSSRR_SRE | HSSRR_SRCYC_DEF_VAL); } /* Set baudrate */ uart_rcar_set_baudrate(dev, cfg->baudrate); /* FIFOs data count trigger configuration */ reg_val = uart_rcar_read_16(dev, SCFCR); reg_val &= ~(SCFCR_RTRG1 | SCFCR_RTRG0 | SCFCR_TTRG1 | SCFCR_TTRG0 | SCFCR_MCE | SCFCR_TFRST | SCFCR_RFRST); uart_rcar_write_16(dev, SCFCR, reg_val); /* Enable Transmit & Receive + disable Interrupts */ reg_val = uart_rcar_read_16(dev, SCSCR); reg_val |= (SCSCR_TE | SCSCR_RE); reg_val &= ~(SCSCR_TIE | SCSCR_RIE | SCSCR_TEIE | SCSCR_REIE | SCSCR_TOIE); uart_rcar_write_16(dev, SCSCR, reg_val); data->current_config = *cfg; k_spin_unlock(&data->lock, key); return 0; } #ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE static int uart_rcar_config_get(const struct device *dev, struct uart_config *cfg) { struct uart_rcar_data *data = dev->data; *cfg = data->current_config; return 0; } #endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */ static int uart_rcar_init(const struct device *dev) { const struct uart_rcar_cfg *config = dev->config; struct uart_rcar_data *data = dev->data; int ret; /* Configure dt provided device signals when available */ ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); if (ret < 0) { return ret; } if (!device_is_ready(config->clock_dev)) { return -ENODEV; } ret = clock_control_on(config->clock_dev, (clock_control_subsys_t)&config->mod_clk); if (ret < 0) { return ret; } ret = clock_control_get_rate(config->clock_dev, (clock_control_subsys_t)&config->bus_clk, &data->clk_rate); if (ret < 0) { return ret; } DEVICE_MMIO_MAP(dev, K_MEM_CACHE_NONE); ret = uart_rcar_configure(dev, &data->current_config); if (ret != 0) { return ret; } #ifdef CONFIG_UART_INTERRUPT_DRIVEN config->irq_config_func(dev); #endif return 0; } #ifdef CONFIG_UART_INTERRUPT_DRIVEN static bool uart_rcar_irq_is_enabled(const struct device *dev, uint32_t irq) { return !!(uart_rcar_read_16(dev, SCSCR) & irq); } static int uart_rcar_fifo_fill(const struct device *dev, const uint8_t *tx_data, int len) { struct uart_rcar_data *data = dev->data; int num_tx = 0; uint16_t reg_val; k_spinlock_key_t key = k_spin_lock(&data->lock); while (((len - num_tx) > 0) && (uart_rcar_read_16(dev, SCFSR) & SCFSR_TDFE)) { /* Send current byte */ uart_rcar_write_8(dev, SCFTDR, tx_data[num_tx]); reg_val = uart_rcar_read_16(dev, SCFSR); reg_val &= ~(SCFSR_TDFE | SCFSR_TEND); uart_rcar_write_16(dev, SCFSR, reg_val); num_tx++; } k_spin_unlock(&data->lock, key); return num_tx; } static int uart_rcar_fifo_read(const struct device *dev, uint8_t *rx_data, const int size) { struct uart_rcar_data *data = dev->data; int num_rx = 0; uint16_t reg_val; k_spinlock_key_t key = k_spin_lock(&data->lock); while (((size - num_rx) > 0) && (uart_rcar_read_16(dev, SCFSR) & SCFSR_RDF)) { /* Receive current byte */ rx_data[num_rx++] = uart_rcar_read_8(dev, SCFRDR); reg_val = uart_rcar_read_16(dev, SCFSR); reg_val &= ~(SCFSR_RDF); uart_rcar_write_16(dev, SCFSR, reg_val); } k_spin_unlock(&data->lock, key); return num_rx; } static void uart_rcar_irq_tx_enable(const struct device *dev) { struct uart_rcar_data *data = dev->data; uint16_t reg_val; k_spinlock_key_t key = k_spin_lock(&data->lock); reg_val = uart_rcar_read_16(dev, SCSCR); reg_val |= (SCSCR_TIE); uart_rcar_write_16(dev, SCSCR, reg_val); k_spin_unlock(&data->lock, key); } static void uart_rcar_irq_tx_disable(const struct device *dev) { struct uart_rcar_data *data = dev->data; uint16_t reg_val; k_spinlock_key_t key = k_spin_lock(&data->lock); reg_val = uart_rcar_read_16(dev, SCSCR); reg_val &= ~(SCSCR_TIE); uart_rcar_write_16(dev, SCSCR, reg_val); k_spin_unlock(&data->lock, key); } static int uart_rcar_irq_tx_ready(const struct device *dev) { return !!(uart_rcar_read_16(dev, SCFSR) & SCFSR_TDFE); } static void uart_rcar_irq_rx_enable(const struct device *dev) { struct uart_rcar_data *data = dev->data; uint16_t reg_val; k_spinlock_key_t key = k_spin_lock(&data->lock); reg_val = uart_rcar_read_16(dev, SCSCR); reg_val |= (SCSCR_RIE); uart_rcar_write_16(dev, SCSCR, reg_val); k_spin_unlock(&data->lock, key); } static void uart_rcar_irq_rx_disable(const struct device *dev) { struct uart_rcar_data *data = dev->data; uint16_t reg_val; k_spinlock_key_t key = k_spin_lock(&data->lock); reg_val = uart_rcar_read_16(dev, SCSCR); reg_val &= ~(SCSCR_RIE); uart_rcar_write_16(dev, SCSCR, reg_val); k_spin_unlock(&data->lock, key); } static int uart_rcar_irq_rx_ready(const struct device *dev) { return !!(uart_rcar_read_16(dev, SCFSR) & SCFSR_RDF); } static void uart_rcar_irq_err_enable(const struct device *dev) { struct uart_rcar_data *data = dev->data; uint16_t reg_val; k_spinlock_key_t key = k_spin_lock(&data->lock); reg_val = uart_rcar_read_16(dev, SCSCR); reg_val |= (SCSCR_REIE); uart_rcar_write_16(dev, SCSCR, reg_val); k_spin_unlock(&data->lock, key); } static void uart_rcar_irq_err_disable(const struct device *dev) { struct uart_rcar_data *data = dev->data; uint16_t reg_val; k_spinlock_key_t key = k_spin_lock(&data->lock); reg_val = uart_rcar_read_16(dev, SCSCR); reg_val &= ~(SCSCR_REIE); uart_rcar_write_16(dev, SCSCR, reg_val); k_spin_unlock(&data->lock, key); } static int uart_rcar_irq_is_pending(const struct device *dev) { return (uart_rcar_irq_rx_ready(dev) && uart_rcar_irq_is_enabled(dev, SCSCR_RIE)) || (uart_rcar_irq_tx_ready(dev) && uart_rcar_irq_is_enabled(dev, SCSCR_TIE)); } static int uart_rcar_irq_update(const struct device *dev) { return 1; } static void uart_rcar_irq_callback_set(const struct device *dev, uart_irq_callback_user_data_t cb, void *cb_data) { struct uart_rcar_data *data = dev->data; data->callback = cb; data->cb_data = cb_data; } /** * @brief Interrupt service routine. * * This simply calls the callback function, if one exists. * * @param arg Argument to ISR. */ void uart_rcar_isr(const struct device *dev) { struct uart_rcar_data *data = dev->data; if (data->callback) { data->callback(dev, data->cb_data); } } #endif /* CONFIG_UART_INTERRUPT_DRIVEN */ static DEVICE_API(uart, uart_rcar_driver_api) = { .poll_in = uart_rcar_poll_in, .poll_out = uart_rcar_poll_out, #ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE .configure = uart_rcar_configure, .config_get = uart_rcar_config_get, #endif #ifdef CONFIG_UART_INTERRUPT_DRIVEN .fifo_fill = uart_rcar_fifo_fill, .fifo_read = uart_rcar_fifo_read, .irq_tx_enable = uart_rcar_irq_tx_enable, .irq_tx_disable = uart_rcar_irq_tx_disable, .irq_tx_ready = uart_rcar_irq_tx_ready, .irq_rx_enable = uart_rcar_irq_rx_enable, .irq_rx_disable = uart_rcar_irq_rx_disable, .irq_rx_ready = uart_rcar_irq_rx_ready, .irq_err_enable = uart_rcar_irq_err_enable, .irq_err_disable = uart_rcar_irq_err_disable, .irq_is_pending = uart_rcar_irq_is_pending, .irq_update = uart_rcar_irq_update, .irq_callback_set = uart_rcar_irq_callback_set, #endif /* CONFIG_UART_INTERRUPT_DRIVEN */ }; /* Device Instantiation */ #define UART_RCAR_DECLARE_CFG(n, IRQ_FUNC_INIT, compat) \ PINCTRL_DT_INST_DEFINE(n); \ static const struct uart_rcar_cfg uart_rcar_cfg_##compat##n = { \ DEVICE_MMIO_ROM_INIT(DT_DRV_INST(n)), \ .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \ .mod_clk.module = DT_INST_CLOCKS_CELL_BY_IDX(n, 0, module), \ .mod_clk.domain = DT_INST_CLOCKS_CELL_BY_IDX(n, 0, domain), \ .bus_clk.module = DT_INST_CLOCKS_CELL_BY_IDX(n, 1, module), \ .bus_clk.domain = DT_INST_CLOCKS_CELL_BY_IDX(n, 1, domain), \ .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ .is_hscif = DT_INST_NODE_HAS_COMPAT(n, renesas_rcar_hscif), \ IRQ_FUNC_INIT \ } #ifdef CONFIG_UART_INTERRUPT_DRIVEN #define UART_RCAR_CONFIG_FUNC(n, compat) \ static void irq_config_func_##compat##n(const struct device *dev) \ { \ IRQ_CONNECT(DT_INST_IRQN(n), \ DT_INST_IRQ(n, priority), \ uart_rcar_isr, \ DEVICE_DT_INST_GET(n), 0); \ \ irq_enable(DT_INST_IRQN(n)); \ } #define UART_RCAR_IRQ_CFG_FUNC_INIT(n, compat) \ .irq_config_func = irq_config_func_##compat##n #define UART_RCAR_INIT_CFG(n, compat) \ UART_RCAR_DECLARE_CFG(n, UART_RCAR_IRQ_CFG_FUNC_INIT(n, compat), compat) #else #define UART_RCAR_CONFIG_FUNC(n, compat) #define UART_RCAR_IRQ_CFG_FUNC_INIT #define UART_RCAR_INIT_CFG(n, compat) \ UART_RCAR_DECLARE_CFG(n, UART_RCAR_IRQ_CFG_FUNC_INIT, compat) #endif #define UART_RCAR_INIT(n, compat) \ static struct uart_rcar_data uart_rcar_data_##compat##n = { \ .current_config = { \ .baudrate = DT_INST_PROP(n, current_speed), \ .parity = UART_CFG_PARITY_NONE, \ .stop_bits = UART_CFG_STOP_BITS_1, \ .data_bits = UART_CFG_DATA_BITS_8, \ .flow_ctrl = UART_CFG_FLOW_CTRL_NONE, \ }, \ }; \ \ static const struct uart_rcar_cfg uart_rcar_cfg_##compat##n; \ \ DEVICE_DT_INST_DEFINE(n, \ uart_rcar_init, \ NULL, \ &uart_rcar_data_##compat##n, \ &uart_rcar_cfg_##compat##n, \ PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, \ &uart_rcar_driver_api); \ \ UART_RCAR_CONFIG_FUNC(n, compat) \ \ UART_RCAR_INIT_CFG(n, compat); DT_INST_FOREACH_STATUS_OKAY_VARGS(UART_RCAR_INIT, DT_DRV_COMPAT) #undef DT_DRV_COMPAT #define DT_DRV_COMPAT renesas_rcar_hscif DT_INST_FOREACH_STATUS_OKAY_VARGS(UART_RCAR_INIT, DT_DRV_COMPAT)