From patchwork Mon Jan 11 19:55:54 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Sperl X-Patchwork-Id: 8008871 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 7AD4D9F1C0 for ; Mon, 11 Jan 2016 19:59:05 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 927D620142 for ; Mon, 11 Jan 2016 19:59:04 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 5A97320165 for ; Mon, 11 Jan 2016 19:59:03 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1aIiaY-00073J-Vo; Mon, 11 Jan 2016 19:57:14 +0000 Received: from 212-186-180-163.dynamic.surfer.at ([212.186.180.163] helo=cgate.sperl.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1aIiaJ-0006xr-S4; Mon, 11 Jan 2016 19:57:01 +0000 Received: from raspcm.intern.sperl.org (account martin@sperl.org [10.10.10.41] verified) by sperl.org (CommuniGate Pro SMTP 6.1.2) with ESMTPSA id 6391459; Mon, 11 Jan 2016 19:56:19 +0000 From: kernel@martin.sperl.org To: Michael Turquette , Stephen Boyd , Stephen Warren , Lee Jones , Eric Anholt , Remi Pommarel , linux-clk@vger.kernel.org, linux-rpi-kernel@lists.infradead.org, linux-arm-kernel@lists.infradead.org, devicetree@vger.kernel.org Subject: [PATCH V2 2/4] clk: bcm2835: enable fractional and mash support Date: Mon, 11 Jan 2016 19:55:54 +0000 Message-Id: <1452542157-2387-3-git-send-email-kernel@martin.sperl.org> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1452542157-2387-1-git-send-email-kernel@martin.sperl.org> References: <1452542157-2387-1-git-send-email-kernel@martin.sperl.org> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20160111_115700_420275_92BA8AF6 X-CRM114-Status: GOOD ( 13.67 ) X-Spam-Score: -0.9 (/) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Martin Sperl MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Martin Sperl The clk-bcm2835 driver right now does the correct calculation of the fractional clock divider, but it does not set the FRAC bit to enable the fractual clock divider in HW This patch enables FRAC for all clocks with frac_bits > 0 but allows to define the selection of a higher-order MASH support instead of just FRAC. Right now there are no limits imposed on maximum frequencies when using MASH/FRAC is enabled. There is a documented limit of 25MHz for MASH, but it is not stated if this also applies to clock dividers that only support FRAC and not MASH. As for how higher order MASH works the following may give some insight: http://www.aholme.co.uk/Frac2/Mash.htm Signed-off-by: Martin Sperl --- drivers/clk/bcm/clk-bcm2835.c | 50 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) -- 1.7.10.4 diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c index 759202a..7c782d3 100644 --- a/drivers/clk/bcm/clk-bcm2835.c +++ b/drivers/clk/bcm/clk-bcm2835.c @@ -115,6 +115,13 @@ # define CM_GATE BIT(CM_GATE_BIT) # define CM_BUSY BIT(7) # define CM_BUSYD BIT(8) +# define CM_MASH_BITS 2 +# define CM_MASH_SHIFT 9 +# define CM_MASH_MASK GENMASK(10, 9) +# define CM_MASH(v) ((v << CM_MASH_SHIFT) & CM_MASH_MASK) +# define CM_MASH_FRAC CM_MASH(1) +# define CM_MASH_2ND_ORDER CM_MASH(2) +# define CM_MASH_3RD_ORDER CM_MASH(3) # define CM_SRC_SHIFT 0 # define CM_SRC_BITS 4 # define CM_SRC_MASK 0xf @@ -632,6 +639,8 @@ struct bcm2835_clock_data { u32 int_bits; /* Number of fractional bits in the divider */ u32 frac_bits; + /* the mash value to use - see CM_MASH and CM_MASH_FRAC/ORDER */ + u32 mash; bool is_vpu_clock; }; @@ -1274,9 +1283,50 @@ static int bcm2835_clock_set_rate(struct clk_hw *hw, struct bcm2835_cprman *cprman = clock->cprman; const struct bcm2835_clock_data *data = clock->data; u32 div = bcm2835_clock_choose_div(hw, rate, parent_rate, false); + u32 ctl, mash; + bool enabled; + spin_lock(&cprman->regs_lock); + /* check if divider is identical, then return */ + if (div == cprman_read(cprman, data->div_reg)) + goto unlock; + + /* it is recommended to only set clock registers when disabled */ + ctl = cprman_read(cprman, data->ctl_reg); + enabled = ctl & CM_ENABLE; + if (enabled) { + /* disable clock */ + cprman_write(cprman, data->ctl_reg, ctl); + + /* release lock while busy waiting */ + spin_unlock(&cprman->regs_lock); + bcm2835_clock_wait_busy(clock); + spin_lock(&cprman->regs_lock); + + /* read the register again */ + ctl = cprman_read(cprman, data->ctl_reg); + } + + /* set the divider */ cprman_write(cprman, data->div_reg, div); + /* set frac/mash if necessarry */ + mash = 0; + if ((data->frac_bits) && (div & GENMASK(CM_DIV_FRAC_BITS, 0))) + mash = (data->mash) ? data->mash : CM_MASH_FRAC; + + /* set mash to the selected value */ + ctl &= ~CM_MASH_MASK; + ctl |= mash & CM_MASH_MASK; + cprman_write(cprman, data->ctl_reg, ctl); + + /* re-enable the clock */ + if (enabled) + cprman_write(cprman, data->ctl_reg, ctl | CM_ENABLE); + +unlock: + spin_unlock(&cprman->regs_lock); + return 0; }