From patchwork Mon May 5 20:09:22 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Murphy X-Patchwork-Id: 29669 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-ie0-f198.google.com (mail-ie0-f198.google.com [209.85.223.198]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id B339F2107B for ; Mon, 5 May 2014 20:10:04 +0000 (UTC) Received: by mail-ie0-f198.google.com with SMTP id rp18sf44621606iec.1 for ; Mon, 05 May 2014 13:10:03 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:delivered-to:from:to:cc:subject:date:message-id :in-reply-to:references:mime-version:sender:precedence:list-id :x-original-sender:x-original-authentication-results:mailing-list :list-post:list-help:list-archive:list-unsubscribe:content-type; bh=ix7j57l4rg+F//ZGv2egoBaOMJlz+VONugBdxmPzq1o=; b=OG8GWmVJTI3pKLqxl50b8Wsq9ToqCgXeEW0d1QYlBXzi9xt06EAkec4hbvemRUOg8d 52Ihe6118wcvrAKeMFBmG/Wse2/zEBeuafBVSfAP2RBHgI/hUuOII6rKHFzc3NiRdOla 70wbB1qTrzsfjbt+oumOXIVnfXIMSyvvSSTsw2Jr3gOXdmi4D8kbd7AOcxLXDtQP5Xvx WQEKmjO8U9qFVJOEW4z9zExtlyAwceqQbujn97LRUjZUJAON1mZ8VmZ1JNTdE45pkOC4 kcQNKNOy/KIRE7jADZP1+wDKD/XayZF07ytdojq4xTZJkbM4vI6aIi3q+mNepS9xPO5x kbnA== X-Gm-Message-State: ALoCoQmwyfhbjbUcOd9gyWiLsPjD5b41P601KXdyQHCT6VjsU1Khhqrcb8SfAoRn+xzEdR9N760b X-Received: by 10.182.98.230 with SMTP id el6mr18345103obb.10.1399320603841; Mon, 05 May 2014 13:10:03 -0700 (PDT) X-BeenThere: patchwork-forward@linaro.org Received: by 10.140.106.201 with SMTP id e67ls2788641qgf.94.gmail; Mon, 05 May 2014 13:10:03 -0700 (PDT) X-Received: by 10.58.243.4 with SMTP id wu4mr1469480vec.67.1399320603681; Mon, 05 May 2014 13:10:03 -0700 (PDT) Received: from mail-vc0-f181.google.com (mail-vc0-f181.google.com [209.85.220.181]) by mx.google.com with ESMTPS id tb2si382235vdc.3.2014.05.05.13.10.03 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Mon, 05 May 2014 13:10:03 -0700 (PDT) Received-SPF: none (google.com: patch+caf_=patchwork-forward=linaro.org@linaro.org does not designate permitted sender hosts) client-ip=209.85.220.181; Received: by mail-vc0-f181.google.com with SMTP id hy4so9216960vcb.26 for ; Mon, 05 May 2014 13:10:03 -0700 (PDT) X-Received: by 10.220.183.4 with SMTP id ce4mr1465924vcb.54.1399320603549; Mon, 05 May 2014 13:10:03 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.220.221.72 with SMTP id ib8csp168703vcb; Mon, 5 May 2014 13:10:03 -0700 (PDT) X-Received: by 10.66.141.197 with SMTP id rq5mr76718278pab.64.1399320602369; Mon, 05 May 2014 13:10:02 -0700 (PDT) Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id gr5si9622607pac.155.2014.05.05.13.10.01; Mon, 05 May 2014 13:10:01 -0700 (PDT) Received-SPF: none (google.com: linux-omap-owner@vger.kernel.org does not designate permitted sender hosts) client-ip=209.132.180.67; Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754214AbaEEUKA (ORCPT + 6 others); Mon, 5 May 2014 16:10:00 -0400 Received: from comal.ext.ti.com ([198.47.26.152]:40388 "EHLO comal.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753406AbaEEUJ4 (ORCPT ); Mon, 5 May 2014 16:09:56 -0400 Received: from dflxv15.itg.ti.com ([128.247.5.124]) by comal.ext.ti.com (8.13.7/8.13.7) with ESMTP id s45K9V3L014188; Mon, 5 May 2014 15:09:31 -0500 Received: from DFLE72.ent.ti.com (dfle72.ent.ti.com [128.247.5.109]) by dflxv15.itg.ti.com (8.14.3/8.13.8) with ESMTP id s45K9Uee025318; Mon, 5 May 2014 15:09:30 -0500 Received: from dflp32.itg.ti.com (10.64.6.15) by DFLE72.ent.ti.com (128.247.5.109) with Microsoft SMTP Server id 14.3.174.1; Mon, 5 May 2014 15:09:30 -0500 Received: from legion.dal.design.ti.com (legion.dal.design.ti.com [128.247.22.53]) by dflp32.itg.ti.com (8.14.3/8.13.8) with ESMTP id s45K9Uhr030869; Mon, 5 May 2014 15:09:30 -0500 Received: from localhost (j-172-22-140-142.vpn.ti.com [172.22.140.142]) by legion.dal.design.ti.com (8.11.7p1+Sun/8.11.7) with ESMTP id s45K9Ut09734; Mon, 5 May 2014 15:09:30 -0500 (CDT) From: Dan Murphy To: , , , CC: Dan Murphy Subject: [RFC] [v2 Patch 1/6] drivers: reset: TI: SoC reset controller support. Date: Mon, 5 May 2014 15:09:22 -0500 Message-ID: <1399320567-3639-2-git-send-email-dmurphy@ti.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1399320567-3639-1-git-send-email-dmurphy@ti.com> References: <1399320567-3639-1-git-send-email-dmurphy@ti.com> MIME-Version: 1.0 Sender: linux-omap-owner@vger.kernel.org Precedence: list List-ID: X-Mailing-List: linux-omap@vger.kernel.org X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: dmurphy@ti.com X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: patch+caf_=patchwork-forward=linaro.org@linaro.org does not designate permitted sender hosts) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , The TI SoC reset controller support utilizes the reset controller framework to give device drivers or function drivers a common set of APIs to call to reset a module. The reset-ti is a common interface to the reset framework. The register data is retrieved during initialization of the reset driver through the reset-ti-data file. The array of data is associated with the compatible from the respective DT entry. Once the data is available then this is derefenced within the common interface. The device driver has the ability to assert, deassert or perform a complete reset. This code was derived from previous work by Rajendra Nayak and Afzal Mohammed. The code was changed to adopt to the reset core and abstract away the SoC information. Signed-off-by: Dan Murphy --- drivers/reset/Kconfig | 1 + drivers/reset/Makefile | 1 + drivers/reset/ti/Kconfig | 8 ++ drivers/reset/ti/Makefile | 1 + drivers/reset/ti/reset-ti-data.h | 56 ++++++++ drivers/reset/ti/reset-ti.c | 267 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 334 insertions(+) create mode 100644 drivers/reset/ti/Kconfig create mode 100644 drivers/reset/ti/Makefile create mode 100644 drivers/reset/ti/reset-ti-data.h create mode 100644 drivers/reset/ti/reset-ti.c diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 0615f50..a58d789 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -13,3 +13,4 @@ menuconfig RESET_CONTROLLER If unsure, say no. source "drivers/reset/sti/Kconfig" +source "drivers/reset/ti/Kconfig" diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 4f60caf..1c8c444 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_RESET_CONTROLLER) += core.o obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o obj-$(CONFIG_ARCH_STI) += sti/ +obj-$(CONFIG_RESET_TI) += ti/ diff --git a/drivers/reset/ti/Kconfig b/drivers/reset/ti/Kconfig new file mode 100644 index 0000000..dcdce90 --- /dev/null +++ b/drivers/reset/ti/Kconfig @@ -0,0 +1,8 @@ +config RESET_TI + depends on RESET_CONTROLLER + bool "TI reset controller" + help + Reset controller support for TI SoC's + + Reset controller found in TI's AM series of SoC's like + AM335x and AM43x and OMAP SoC's like OMAP5 and DRA7 diff --git a/drivers/reset/ti/Makefile b/drivers/reset/ti/Makefile new file mode 100644 index 0000000..55ab3f5 --- /dev/null +++ b/drivers/reset/ti/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_RESET_TI) += reset-ti.o diff --git a/drivers/reset/ti/reset-ti-data.h b/drivers/reset/ti/reset-ti-data.h new file mode 100644 index 0000000..4d2a6d5 --- /dev/null +++ b/drivers/reset/ti/reset-ti-data.h @@ -0,0 +1,56 @@ +/* + * PRCM reset driver for TI SoC's + * + * Copyright 2014 Texas Instruments Inc. + * + * Author: Dan Murphy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _RESET_TI_DATA_H_ +#define _RESET_TI_DATA_H_ + +#include +#include + +/** + * struct ti_reset_reg_data - Structure of the reset register information + * for a particular SoC. + * @rstctrl_offs: This is the reset control offset value from + * from the parent reset node. + * @rstst_offs: This is the reset status offset value from + * from the parent reset node. + * @rstctrl_bit: This is the reset control bit for the module. + * @rstst_bit: This is the reset status bit for the module. + * + * This structure describes the reset register control and status offsets. + * The bits are also defined for the same. + */ +struct ti_reset_reg_data { + void __iomem *reg_base; + u32 rstctrl_offs; + u32 rstst_offs; + u32 rstctrl_bit; + u32 rstst_bit; +}; + +/** + * struct ti_reset_data - Structure that contains the reset register data + * as well as the total number of resets for a particular SoC. + * @reg_data: Pointer to the register data structure. + * @nr_resets: Total number of resets for the SoC in the reset array. + * + * This structure contains a pointer to the register data and the modules + * register base. The number of resets and reset controller device data is + * stored within this structure. + * + */ +struct ti_reset_data { + struct ti_reset_reg_data *reg_data; + struct reset_controller_dev rcdev; +}; + +#endif diff --git a/drivers/reset/ti/reset-ti.c b/drivers/reset/ti/reset-ti.c new file mode 100644 index 0000000..349f4fb --- /dev/null +++ b/drivers/reset/ti/reset-ti.c @@ -0,0 +1,267 @@ +/* + * PRCM reset driver for TI SoC's + * + * Copyright 2014 Texas Instruments Inc. + * + * Author: Dan Murphy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "reset-ti-data.h" + +#define DRIVER_NAME "prcm_reset_ti" + +static struct ti_reset_data *ti_data; + +static int ti_reset_get_of_data(struct ti_reset_reg_data *reset_data, + unsigned long id) +{ + struct device_node *dev_node; + struct device_node *parent; + struct device_node *prcm_parent; + struct device_node *reset_parent; + int ret = -EINVAL; + + dev_node = of_find_node_by_phandle((phandle) id); + if (!dev_node) { + pr_err("%s: Cannot find phandle node\n", __func__); + return ret; + } + + /* node parent */ + parent = of_get_parent(dev_node); + if (!parent) { + pr_err("%s: Cannot find parent reset node\n", __func__); + return ret; + } + /* prcm reset parent */ + reset_parent = of_get_next_parent(parent); + if (!reset_parent) { + pr_err("%s: Cannot find parent reset node\n", __func__); + return ret; + } + /* PRCM Parent */ + reset_parent = of_get_parent(reset_parent); + if (!prcm_parent) { + pr_err("%s: Cannot find parent reset node\n", __func__); + return ret; + } + + reset_data->reg_base = of_iomap(reset_parent, 0); + if (!reset_data->reg_base) { + pr_err("%s: Cannot map reset parent.\n", __func__); + return ret; + } + + ret = of_property_read_u32_index(parent, "reg", 0, + &reset_data->rstctrl_offs); + if (ret) + return ret; + + ret = of_property_read_u32_index(parent, "reg", 1, + &reset_data->rstst_offs); + if (ret) + return ret; + + ret = of_property_read_u32(dev_node, "control-bit", + &reset_data->rstctrl_bit); + if (ret < 0) + pr_err("%s: No entry in %s for rstst_offs\n", __func__, + dev_node->name); + + ret = of_property_read_u32(dev_node, "status-bit", + &reset_data->rstst_bit); + if (ret < 0) + pr_err("%s: No entry in %s for rstst_offs\n", __func__, + dev_node->name); + + return 0; +} + +static void ti_reset_wait_on_reset(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct ti_reset_reg_data *temp_reg_data; + void __iomem *status_reg; + u32 bit_mask = 0; + u32 val = 0; + + temp_reg_data = kzalloc(sizeof(struct ti_reset_reg_data), GFP_KERNEL); + ti_reset_get_of_data(temp_reg_data, id); + + /* Clear the reset status bit to reflect the current status */ + status_reg = temp_reg_data->reg_base + temp_reg_data->rstst_offs; + bit_mask = temp_reg_data->rstst_bit; + do { + val = readl(status_reg); + if (!(val & (1 << bit_mask))) + break; + } while (1); +} + +static int ti_reset_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct ti_reset_reg_data *temp_reg_data; + void __iomem *reg; + void __iomem *status_reg; + u32 status_bit = 0; + u32 bit_mask = 0; + u32 val = 0; + + temp_reg_data = kzalloc(sizeof(struct ti_reset_reg_data), GFP_KERNEL); + ti_reset_get_of_data(temp_reg_data, id); + + /* Clear the reset status bit to reflect the current status */ + status_reg = temp_reg_data->reg_base + temp_reg_data->rstst_offs; + status_bit = temp_reg_data->rstst_bit; + writel(1 << status_bit, status_reg); + + reg = temp_reg_data->reg_base + temp_reg_data->rstctrl_offs; + bit_mask = temp_reg_data->rstctrl_bit; + val = readl(reg); + if (!(val & bit_mask)) { + val |= bit_mask; + writel(val, reg); + } + + kfree(temp_reg_data); + + return 0; +} + +static int ti_reset_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + + struct ti_reset_reg_data *temp_reg_data; + void __iomem *reg; + void __iomem *status_reg; + u32 status_bit = 0; + u32 bit_mask = 0; + u32 val = 0; + + temp_reg_data = kzalloc(sizeof(struct ti_reset_reg_data), GFP_KERNEL); + ti_reset_get_of_data(temp_reg_data, id); + + /* Clear the reset status bit to reflect the current status */ + status_reg = temp_reg_data->reg_base + temp_reg_data->rstst_offs; + status_bit = temp_reg_data->rstst_bit; + writel(1 << status_bit, status_reg); + + reg = temp_reg_data->reg_base + temp_reg_data->rstctrl_offs; + bit_mask = temp_reg_data->rstctrl_bit; + val = readl(reg); + if (val & bit_mask) { + val &= ~bit_mask; + writel(val, reg); + } + + return 0; +} + +static int ti_reset_reset(struct reset_controller_dev *rcdev, + unsigned long id) +{ + ti_reset_assert(rcdev, id); + ti_reset_deassert(rcdev, id); + ti_reset_wait_on_reset(rcdev, id); + + return 0; +} + +static int ti_reset_xlate(struct reset_controller_dev *rcdev, + const struct of_phandle_args *reset_spec) +{ + struct device_node *dev_node; + + if (WARN_ON(reset_spec->args_count != rcdev->of_reset_n_cells)) + return -EINVAL; + + /* Verify that the phandle exists */ + dev_node = of_find_node_by_phandle((phandle) reset_spec->args[0]); + if (!dev_node) { + pr_err("%s: Cannot find phandle node\n", __func__); + return -EINVAL; + } + + return reset_spec->args[0]; +} + +static struct reset_control_ops ti_reset_ops = { + .reset = ti_reset_reset, + .assert = ti_reset_assert, + .deassert = ti_reset_deassert, +}; + +static int ti_reset_probe(struct platform_device *pdev) +{ + struct device_node *resets; + + resets = of_find_node_by_name(NULL, "resets"); + if (!resets) { + pr_err("%s: missing 'resets' child node.\n", __func__); + return -EINVAL; + } + + ti_data = kzalloc(sizeof(*ti_data), GFP_KERNEL); + if (!ti_data) + return -ENOMEM; + + ti_data->rcdev.owner = THIS_MODULE; + ti_data->rcdev.of_node = resets; + ti_data->rcdev.ops = &ti_reset_ops; + + ti_data->rcdev.of_reset_n_cells = 1; + ti_data->rcdev.of_xlate = &ti_reset_xlate; + + reset_controller_register(&ti_data->rcdev); + + return 0; +} + +static int ti_reset_remove(struct platform_device *pdev) +{ + reset_controller_unregister(&ti_data->rcdev); + + return 0; +} + +static const struct of_device_id ti_reset_of_match[] = { + { .compatible = "ti,omap5-prm" }, + { .compatible = "ti,omap4-prm" }, + { .compatible = "ti,omap5-prm" }, + { .compatible = "ti,dra7-prm" }, + { .compatible = "ti,am4-prcm" }, + { .compatible = "ti,am3-prcm" }, + {}, +}; + +static struct platform_driver ti_reset_driver = { + .probe = ti_reset_probe, + .remove = ti_reset_remove, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(ti_reset_of_match), + }, +}; +module_platform_driver(ti_reset_driver); + +MODULE_DESCRIPTION("PRCM reset driver for TI SoCs"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRIVER_NAME);