blob: 45617e3fd1a960f6f7b53f10c90d99f39015b3c7 [file] [log] [blame]
/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/elf.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/clk.h>
#include <linux/timer.h>
#include <linux/jiffies.h>
#include <linux/platform_device.h>
#include <asm/mach-types.h>
#include <mach/scm.h>
#include <mach/msm_iomap.h>
#include "peripheral-loader.h"
#include "scm-pas.h"
#define PPSS_RESET (MSM_CLK_CTL_BASE + 0x2594)
#define PPSS_PROC_CLK_CTL (MSM_CLK_CTL_BASE + 0x2588)
#define CLK_HALT_DFAB_STATE (MSM_CLK_CTL_BASE + 0x2FC8)
static int dsps_start;
static int init_image_dsps_trusted(struct pil_desc *pil, const u8 *metadata,
size_t size)
{
return pas_init_image(PAS_DSPS, metadata, size);
}
static int init_image_dsps_untrusted(struct pil_desc *pil, const u8 *metadata,
size_t size)
{
struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
dsps_start = ehdr->e_entry;
/* Bring memory and bus interface out of reset */
__raw_writel(0x2, PPSS_RESET);
mb();
return 0;
}
static int verify_blob(struct pil_desc *pil, u32 phy_addr, size_t size)
{
return 0;
}
static int reset_dsps_untrusted(struct pil_desc *pil)
{
__raw_writel(0x10, PPSS_PROC_CLK_CTL);
while (__raw_readl(CLK_HALT_DFAB_STATE) & BIT(18))
cpu_relax();
/* Bring DSPS out of reset */
__raw_writel(0x0, PPSS_RESET);
return 0;
}
static int reset_dsps_trusted(struct pil_desc *pil)
{
return pas_auth_and_reset(PAS_DSPS);
}
static int shutdown_dsps_trusted(struct pil_desc *pil)
{
return pas_shutdown(PAS_DSPS);
}
static int shutdown_dsps_untrusted(struct pil_desc *pil)
{
__raw_writel(0x3, PPSS_RESET);
__raw_writel(0x0, PPSS_PROC_CLK_CTL);
return 0;
}
struct pil_reset_ops pil_dsps_ops = {
.init_image = init_image_dsps_untrusted,
.verify_blob = verify_blob,
.auth_and_reset = reset_dsps_untrusted,
.shutdown = shutdown_dsps_untrusted,
};
static struct platform_device pil_dsps = {
.name = "pil_dsps",
};
static struct pil_desc pil_dsps_desc = {
.name = "dsps",
.dev = &pil_dsps.dev,
.ops = &pil_dsps_ops,
.owner = THIS_MODULE,
};
static int __init msm_peripheral_reset_init(void)
{
if (pas_supported(PAS_DSPS) > 0) {
pil_dsps_ops.init_image = init_image_dsps_trusted;
pil_dsps_ops.auth_and_reset = reset_dsps_trusted;
pil_dsps_ops.shutdown = shutdown_dsps_trusted;
}
if (machine_is_msm8x60_fluid())
pil_dsps_desc.name = "dsps_fluid";
BUG_ON(platform_device_register(&pil_dsps));
BUG_ON(IS_ERR(msm_pil_register(&pil_dsps_desc)));
return 0;
}
module_init(msm_peripheral_reset_init);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Validate and bring peripherals out of reset");