1*30c8a20dSKhristine Andreea Barbulescu /* 2*30c8a20dSKhristine Andreea Barbulescu * Copyright 2020-2025 NXP 3*30c8a20dSKhristine Andreea Barbulescu * 4*30c8a20dSKhristine Andreea Barbulescu * SPDX-License-Identifier: BSD-3-Clause 5*30c8a20dSKhristine Andreea Barbulescu */ 6*30c8a20dSKhristine Andreea Barbulescu #include <errno.h> 7*30c8a20dSKhristine Andreea Barbulescu 8*30c8a20dSKhristine Andreea Barbulescu #include <common/debug.h> 9*30c8a20dSKhristine Andreea Barbulescu #include <ddr_utils.h> 10*30c8a20dSKhristine Andreea Barbulescu #include <mmio_poll.h> 11*30c8a20dSKhristine Andreea Barbulescu 12*30c8a20dSKhristine Andreea Barbulescu static uint32_t get_mail(uint32_t *mail); 13*30c8a20dSKhristine Andreea Barbulescu static uint32_t ack_mail(void); 14*30c8a20dSKhristine Andreea Barbulescu 15*30c8a20dSKhristine Andreea Barbulescu /* Wait until firmware finishes execution and return training result */ 16*30c8a20dSKhristine Andreea Barbulescu uint32_t wait_firmware_execution(void) 17*30c8a20dSKhristine Andreea Barbulescu { 18*30c8a20dSKhristine Andreea Barbulescu uint32_t timeout_us = DEFAULT_TIMEOUT_US, ret = NO_ERR, mail = 0; 19*30c8a20dSKhristine Andreea Barbulescu uint64_t timeout = timeout_init_us(timeout_us); 20*30c8a20dSKhristine Andreea Barbulescu bool loop_continue = true; 21*30c8a20dSKhristine Andreea Barbulescu bool timeout_expired; 22*30c8a20dSKhristine Andreea Barbulescu 23*30c8a20dSKhristine Andreea Barbulescu do { 24*30c8a20dSKhristine Andreea Barbulescu ret = get_mail(&mail); 25*30c8a20dSKhristine Andreea Barbulescu if (ret != NO_ERR) { 26*30c8a20dSKhristine Andreea Barbulescu loop_continue = false; 27*30c8a20dSKhristine Andreea Barbulescu } else if (mail == TRAINING_FAILED_MSG) { 28*30c8a20dSKhristine Andreea Barbulescu /* Training stage failed */ 29*30c8a20dSKhristine Andreea Barbulescu ret = TRAINING_FAILED; 30*30c8a20dSKhristine Andreea Barbulescu loop_continue = false; 31*30c8a20dSKhristine Andreea Barbulescu } else if (mail == TRAINING_OK_MSG) { 32*30c8a20dSKhristine Andreea Barbulescu loop_continue = false; 33*30c8a20dSKhristine Andreea Barbulescu } else { 34*30c8a20dSKhristine Andreea Barbulescu /* Continue waiting for training result */ 35*30c8a20dSKhristine Andreea Barbulescu } 36*30c8a20dSKhristine Andreea Barbulescu timeout_expired = timeout_elapsed(timeout); 37*30c8a20dSKhristine Andreea Barbulescu if (timeout_expired) { 38*30c8a20dSKhristine Andreea Barbulescu ret = TRAINING_FAILED; 39*30c8a20dSKhristine Andreea Barbulescu loop_continue = false; 40*30c8a20dSKhristine Andreea Barbulescu } 41*30c8a20dSKhristine Andreea Barbulescu /* Continue loop if no exit condition met and timeout not elapsed */ 42*30c8a20dSKhristine Andreea Barbulescu } while (loop_continue); 43*30c8a20dSKhristine Andreea Barbulescu 44*30c8a20dSKhristine Andreea Barbulescu return ret; 45*30c8a20dSKhristine Andreea Barbulescu } 46*30c8a20dSKhristine Andreea Barbulescu 47*30c8a20dSKhristine Andreea Barbulescu /* Acknowledge received message */ 48*30c8a20dSKhristine Andreea Barbulescu static uint32_t ack_mail(void) 49*30c8a20dSKhristine Andreea Barbulescu { 50*30c8a20dSKhristine Andreea Barbulescu uint32_t timeout = DEFAULT_TIMEOUT_US; 51*30c8a20dSKhristine Andreea Barbulescu uint32_t uct_reg; 52*30c8a20dSKhristine Andreea Barbulescu int err; 53*30c8a20dSKhristine Andreea Barbulescu 54*30c8a20dSKhristine Andreea Barbulescu /* ACK message */ 55*30c8a20dSKhristine Andreea Barbulescu mmio_write_32(DDR_PHYA_DCTWRITEPROT, APBONLY_DCTWRITEPROT_ACK_EN); 56*30c8a20dSKhristine Andreea Barbulescu 57*30c8a20dSKhristine Andreea Barbulescu err = mmio_read_32_poll_timeout(DDR_PHYA_APBONLY_UCTSHADOWREGS, uct_reg, 58*30c8a20dSKhristine Andreea Barbulescu (uct_reg & UCT_WRITE_PROT_SHADOW_MASK) != 59*30c8a20dSKhristine Andreea Barbulescu UCT_WRITE_PROT_SHADOW_ACK, 60*30c8a20dSKhristine Andreea Barbulescu timeout); 61*30c8a20dSKhristine Andreea Barbulescu if (err != 0) { 62*30c8a20dSKhristine Andreea Barbulescu ERROR("DDR PHY did not acknowledge write protection\n"); 63*30c8a20dSKhristine Andreea Barbulescu return TIMEOUT_ERR; 64*30c8a20dSKhristine Andreea Barbulescu } 65*30c8a20dSKhristine Andreea Barbulescu 66*30c8a20dSKhristine Andreea Barbulescu mmio_write_32(DDR_PHYA_DCTWRITEPROT, APBONLY_DCTWRITEPROT_ACK_DIS); 67*30c8a20dSKhristine Andreea Barbulescu 68*30c8a20dSKhristine Andreea Barbulescu return NO_ERR; 69*30c8a20dSKhristine Andreea Barbulescu } 70*30c8a20dSKhristine Andreea Barbulescu 71*30c8a20dSKhristine Andreea Barbulescu /* Read available message from DDR PHY microcontroller */ 72*30c8a20dSKhristine Andreea Barbulescu static uint32_t get_mail(uint32_t *mail) 73*30c8a20dSKhristine Andreea Barbulescu { 74*30c8a20dSKhristine Andreea Barbulescu uint32_t uct_reg, timeout = DEFAULT_TIMEOUT_US; 75*30c8a20dSKhristine Andreea Barbulescu int err; 76*30c8a20dSKhristine Andreea Barbulescu 77*30c8a20dSKhristine Andreea Barbulescu err = mmio_read_32_poll_timeout(DDR_PHYA_APBONLY_UCTSHADOWREGS, uct_reg, 78*30c8a20dSKhristine Andreea Barbulescu (uct_reg & UCT_WRITE_PROT_SHADOW_MASK) == 79*30c8a20dSKhristine Andreea Barbulescu UCT_WRITE_PROT_SHADOW_ACK, 80*30c8a20dSKhristine Andreea Barbulescu timeout); 81*30c8a20dSKhristine Andreea Barbulescu if (err != 0) { 82*30c8a20dSKhristine Andreea Barbulescu ERROR("DDR PHY did not acknowledge UCT write protection\n"); 83*30c8a20dSKhristine Andreea Barbulescu return TIMEOUT_ERR; 84*30c8a20dSKhristine Andreea Barbulescu } 85*30c8a20dSKhristine Andreea Barbulescu 86*30c8a20dSKhristine Andreea Barbulescu *mail = mmio_read_32(DDR_PHYA_APBONLY_UCTWRITEONLYSHADOW); 87*30c8a20dSKhristine Andreea Barbulescu /* ACK */ 88*30c8a20dSKhristine Andreea Barbulescu return ack_mail(); 89*30c8a20dSKhristine Andreea Barbulescu } 90