uboot/drivers/remoteproc/stm32_copro.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
   2/*
   3 * Copyright (C) 2019, STMicroelectronics - All Rights Reserved
   4 */
   5#define LOG_CATEGORY UCLASS_REMOTEPROC
   6
   7#include <common.h>
   8#include <dm.h>
   9#include <errno.h>
  10#include <fdtdec.h>
  11#include <log.h>
  12#include <remoteproc.h>
  13#include <reset.h>
  14#include <asm/io.h>
  15#include <dm/device_compat.h>
  16#include <linux/err.h>
  17
  18/**
  19 * struct stm32_copro_privdata - power processor private data
  20 * @reset_ctl:          reset controller handle
  21 * @hold_boot:          hold boot controller handle
  22 * @rsc_table_addr:     resource table address
  23 */
  24struct stm32_copro_privdata {
  25        struct reset_ctl reset_ctl;
  26        struct reset_ctl hold_boot;
  27        ulong rsc_table_addr;
  28};
  29
  30/**
  31 * stm32_copro_probe() - Basic probe
  32 * @dev:        corresponding STM32 remote processor device
  33 * @return 0 if all went ok, else corresponding -ve error
  34 */
  35static int stm32_copro_probe(struct udevice *dev)
  36{
  37        struct stm32_copro_privdata *priv;
  38        int ret;
  39
  40        priv = dev_get_priv(dev);
  41
  42        ret = reset_get_by_name(dev, "mcu_rst", &priv->reset_ctl);
  43        if (ret) {
  44                dev_err(dev, "failed to get reset (%d)\n", ret);
  45                return ret;
  46        }
  47
  48        ret = reset_get_by_name(dev, "hold_boot", &priv->hold_boot);
  49        if (ret) {
  50                dev_err(dev, "failed to get hold boot (%d)\n", ret);
  51                return ret;
  52        }
  53
  54        dev_dbg(dev, "probed\n");
  55
  56        return 0;
  57}
  58
  59/**
  60 * stm32_copro_device_to_virt() - Convert device address to virtual address
  61 * @dev:        corresponding STM32 remote processor device
  62 * @da:         device address
  63 * @size:       Size of the memory region @da is pointing to
  64 * @return converted virtual address
  65 */
  66static void *stm32_copro_device_to_virt(struct udevice *dev, ulong da,
  67                                        ulong size)
  68{
  69        fdt32_t in_addr = cpu_to_be32(da), end_addr;
  70        u64 paddr;
  71
  72        paddr = dev_translate_dma_address(dev, &in_addr);
  73        if (paddr == OF_BAD_ADDR) {
  74                dev_err(dev, "Unable to convert address %ld\n", da);
  75                return NULL;
  76        }
  77
  78        end_addr = cpu_to_be32(da + size - 1);
  79        if (dev_translate_dma_address(dev, &end_addr) == OF_BAD_ADDR) {
  80                dev_err(dev, "Unable to convert address %ld\n", da + size - 1);
  81                return NULL;
  82        }
  83
  84        return phys_to_virt(paddr);
  85}
  86
  87/**
  88 * stm32_copro_load() - Loadup the STM32 remote processor
  89 * @dev:        corresponding STM32 remote processor device
  90 * @addr:       Address in memory where image is stored
  91 * @size:       Size in bytes of the image
  92 * @return 0 if all went ok, else corresponding -ve error
  93 */
  94static int stm32_copro_load(struct udevice *dev, ulong addr, ulong size)
  95{
  96        struct stm32_copro_privdata *priv;
  97        ulong rsc_table_size;
  98        int ret;
  99
 100        priv = dev_get_priv(dev);
 101
 102        ret = reset_assert(&priv->hold_boot);
 103        if (ret) {
 104                dev_err(dev, "Unable to assert hold boot (ret=%d)\n", ret);
 105                return ret;
 106        }
 107
 108        ret = reset_assert(&priv->reset_ctl);
 109        if (ret) {
 110                dev_err(dev, "Unable to assert reset line (ret=%d)\n", ret);
 111                return ret;
 112        }
 113
 114        if (rproc_elf32_load_rsc_table(dev, addr, size, &priv->rsc_table_addr,
 115                                       &rsc_table_size)) {
 116                priv->rsc_table_addr = 0;
 117                dev_warn(dev, "No valid resource table for this firmware\n");
 118        }
 119
 120        return rproc_elf32_load_image(dev, addr, size);
 121}
 122
 123/**
 124 * stm32_copro_start() - Start the STM32 remote processor
 125 * @dev:        corresponding STM32 remote processor device
 126 * @return 0 if all went ok, else corresponding -ve error
 127 */
 128static int stm32_copro_start(struct udevice *dev)
 129{
 130        struct stm32_copro_privdata *priv;
 131        int ret;
 132
 133        priv = dev_get_priv(dev);
 134
 135        ret = reset_deassert(&priv->hold_boot);
 136        if (ret) {
 137                dev_err(dev, "Unable to deassert hold boot (ret=%d)\n", ret);
 138                return ret;
 139        }
 140
 141        /*
 142         * Once copro running, reset hold boot flag to avoid copro
 143         * rebooting autonomously (error should never occur)
 144         */
 145        ret = reset_assert(&priv->hold_boot);
 146        if (ret)
 147                dev_err(dev, "Unable to assert hold boot (ret=%d)\n", ret);
 148
 149        /* indicates that copro is running */
 150        writel(TAMP_COPRO_STATE_CRUN, TAMP_COPRO_STATE);
 151        /* Store rsc_address in bkp register */
 152        writel(priv->rsc_table_addr, TAMP_COPRO_RSC_TBL_ADDRESS);
 153
 154        return 0;
 155}
 156
 157/**
 158 * stm32_copro_reset() - Reset the STM32 remote processor
 159 * @dev:        corresponding STM32 remote processor device
 160 * @return 0 if all went ok, else corresponding -ve error
 161 */
 162static int stm32_copro_reset(struct udevice *dev)
 163{
 164        struct stm32_copro_privdata *priv;
 165        int ret;
 166
 167        priv = dev_get_priv(dev);
 168
 169        ret = reset_assert(&priv->hold_boot);
 170        if (ret) {
 171                dev_err(dev, "Unable to assert hold boot (ret=%d)\n", ret);
 172                return ret;
 173        }
 174
 175        ret = reset_assert(&priv->reset_ctl);
 176        if (ret) {
 177                dev_err(dev, "Unable to assert reset line (ret=%d)\n", ret);
 178                return ret;
 179        }
 180
 181        writel(TAMP_COPRO_STATE_OFF, TAMP_COPRO_STATE);
 182
 183        return 0;
 184}
 185
 186/**
 187 * stm32_copro_stop() - Stop the STM32 remote processor
 188 * @dev:        corresponding STM32 remote processor device
 189 * @return 0 if all went ok, else corresponding -ve error
 190 */
 191static int stm32_copro_stop(struct udevice *dev)
 192{
 193        return stm32_copro_reset(dev);
 194}
 195
 196/**
 197 * stm32_copro_is_running() - Is the STM32 remote processor running
 198 * @dev:        corresponding STM32 remote processor device
 199 * @return 0 if the remote processor is running, 1 otherwise
 200 */
 201static int stm32_copro_is_running(struct udevice *dev)
 202{
 203        return (readl(TAMP_COPRO_STATE) == TAMP_COPRO_STATE_OFF);
 204}
 205
 206static const struct dm_rproc_ops stm32_copro_ops = {
 207        .load = stm32_copro_load,
 208        .start = stm32_copro_start,
 209        .stop =  stm32_copro_stop,
 210        .reset = stm32_copro_reset,
 211        .is_running = stm32_copro_is_running,
 212        .device_to_virt = stm32_copro_device_to_virt,
 213};
 214
 215static const struct udevice_id stm32_copro_ids[] = {
 216        {.compatible = "st,stm32mp1-m4"},
 217        {}
 218};
 219
 220U_BOOT_DRIVER(stm32_copro) = {
 221        .name = "stm32_m4_proc",
 222        .of_match = stm32_copro_ids,
 223        .id = UCLASS_REMOTEPROC,
 224        .ops = &stm32_copro_ops,
 225        .probe = stm32_copro_probe,
 226        .priv_auto      = sizeof(struct stm32_copro_privdata),
 227};
 228