| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Amlogic Meson GX eFuse Driver |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (c) 2016 Endless Computers, Inc. |
|---|
| 5 | 6 | * Author: Carlo Caione <carlo@endlessm.com> |
|---|
| 6 | | - * |
|---|
| 7 | | - * This program is free software; you can redistribute it and/or modify it |
|---|
| 8 | | - * under the terms of version 2 of the GNU General Public License as |
|---|
| 9 | | - * published by the Free Software Foundation. |
|---|
| 10 | | - * |
|---|
| 11 | | - * This program is distributed in the hope that it will be useful, but WITHOUT |
|---|
| 12 | | - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|---|
| 13 | | - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
|---|
| 14 | | - * more details. |
|---|
| 15 | 7 | */ |
|---|
| 16 | 8 | |
|---|
| 9 | +#include <linux/clk.h> |
|---|
| 17 | 10 | #include <linux/module.h> |
|---|
| 18 | 11 | #include <linux/nvmem-provider.h> |
|---|
| 19 | 12 | #include <linux/of.h> |
|---|
| .. | .. |
|---|
| 24 | 17 | static int meson_efuse_read(void *context, unsigned int offset, |
|---|
| 25 | 18 | void *val, size_t bytes) |
|---|
| 26 | 19 | { |
|---|
| 27 | | - return meson_sm_call_read((u8 *)val, bytes, SM_EFUSE_READ, offset, |
|---|
| 20 | + struct meson_sm_firmware *fw = context; |
|---|
| 21 | + |
|---|
| 22 | + return meson_sm_call_read(fw, (u8 *)val, bytes, SM_EFUSE_READ, offset, |
|---|
| 28 | 23 | bytes, 0, 0, 0); |
|---|
| 29 | 24 | } |
|---|
| 30 | 25 | |
|---|
| 31 | 26 | static int meson_efuse_write(void *context, unsigned int offset, |
|---|
| 32 | 27 | void *val, size_t bytes) |
|---|
| 33 | 28 | { |
|---|
| 34 | | - return meson_sm_call_write((u8 *)val, bytes, SM_EFUSE_WRITE, offset, |
|---|
| 29 | + struct meson_sm_firmware *fw = context; |
|---|
| 30 | + |
|---|
| 31 | + return meson_sm_call_write(fw, (u8 *)val, bytes, SM_EFUSE_WRITE, offset, |
|---|
| 35 | 32 | bytes, 0, 0, 0); |
|---|
| 36 | 33 | } |
|---|
| 37 | 34 | |
|---|
| .. | .. |
|---|
| 44 | 41 | static int meson_efuse_probe(struct platform_device *pdev) |
|---|
| 45 | 42 | { |
|---|
| 46 | 43 | struct device *dev = &pdev->dev; |
|---|
| 44 | + struct meson_sm_firmware *fw; |
|---|
| 45 | + struct device_node *sm_np; |
|---|
| 47 | 46 | struct nvmem_device *nvmem; |
|---|
| 48 | 47 | struct nvmem_config *econfig; |
|---|
| 48 | + struct clk *clk; |
|---|
| 49 | 49 | unsigned int size; |
|---|
| 50 | + int ret; |
|---|
| 50 | 51 | |
|---|
| 51 | | - if (meson_sm_call(SM_EFUSE_USER_MAX, &size, 0, 0, 0, 0, 0) < 0) |
|---|
| 52 | + sm_np = of_parse_phandle(pdev->dev.of_node, "secure-monitor", 0); |
|---|
| 53 | + if (!sm_np) { |
|---|
| 54 | + dev_err(&pdev->dev, "no secure-monitor node\n"); |
|---|
| 55 | + return -ENODEV; |
|---|
| 56 | + } |
|---|
| 57 | + |
|---|
| 58 | + fw = meson_sm_get(sm_np); |
|---|
| 59 | + of_node_put(sm_np); |
|---|
| 60 | + if (!fw) |
|---|
| 61 | + return -EPROBE_DEFER; |
|---|
| 62 | + |
|---|
| 63 | + clk = devm_clk_get(dev, NULL); |
|---|
| 64 | + if (IS_ERR(clk)) { |
|---|
| 65 | + ret = PTR_ERR(clk); |
|---|
| 66 | + if (ret != -EPROBE_DEFER) |
|---|
| 67 | + dev_err(dev, "failed to get efuse gate"); |
|---|
| 68 | + return ret; |
|---|
| 69 | + } |
|---|
| 70 | + |
|---|
| 71 | + ret = clk_prepare_enable(clk); |
|---|
| 72 | + if (ret) { |
|---|
| 73 | + dev_err(dev, "failed to enable gate"); |
|---|
| 74 | + return ret; |
|---|
| 75 | + } |
|---|
| 76 | + |
|---|
| 77 | + ret = devm_add_action_or_reset(dev, |
|---|
| 78 | + (void(*)(void *))clk_disable_unprepare, |
|---|
| 79 | + clk); |
|---|
| 80 | + if (ret) { |
|---|
| 81 | + dev_err(dev, "failed to add disable callback"); |
|---|
| 82 | + return ret; |
|---|
| 83 | + } |
|---|
| 84 | + |
|---|
| 85 | + if (meson_sm_call(fw, SM_EFUSE_USER_MAX, &size, 0, 0, 0, 0, 0) < 0) { |
|---|
| 86 | + dev_err(dev, "failed to get max user"); |
|---|
| 52 | 87 | return -EINVAL; |
|---|
| 88 | + } |
|---|
| 53 | 89 | |
|---|
| 54 | 90 | econfig = devm_kzalloc(dev, sizeof(*econfig), GFP_KERNEL); |
|---|
| 55 | 91 | if (!econfig) |
|---|
| .. | .. |
|---|
| 62 | 98 | econfig->reg_read = meson_efuse_read; |
|---|
| 63 | 99 | econfig->reg_write = meson_efuse_write; |
|---|
| 64 | 100 | econfig->size = size; |
|---|
| 101 | + econfig->priv = fw; |
|---|
| 65 | 102 | |
|---|
| 66 | 103 | nvmem = devm_nvmem_register(&pdev->dev, econfig); |
|---|
| 67 | 104 | |
|---|