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