aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/crypto/hifn_795x.c
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2007-11-20 23:47:13 -0500
committerHerbert Xu <herbert@gondor.apana.org.au>2008-01-10 16:16:16 -0500
commit37a8023ce59bfc1fa24067fd94aee7b286f4c01b (patch)
treefda34215b46022c3ae121478ff172e331d9c0b17 /drivers/crypto/hifn_795x.c
parent984e976f5382ff09351ddd3b023937611396d739 (diff)
[HIFN]: Improve PLL initialization
The current PLL initalization has a number of deficiencies: - uses fixed multiplier of 8, which overclocks the chip when using a reference clock that operates at frequencies above 33MHz. According to a comment in the BSD source, this is true for the external clock on almost all every board. - writes to a reserved bit - doesn't follow the initialization procedure specified in chapter 6.11.1 of the HIFN hardware users guide - doesn't allow to use the PCI clock This patch adds a module parameter to specify the reference clock (pci or external) and its frequency and uses that to calculate the optimum multiplier to reach the maximal speed. By default it uses the external clock and assumes a speed of 66MHz, which effectively halfs the frequency currently used. Signed-off-by: Patrick McHardy <kaber@trash.net> Acked-by: Evgeniy Polyakov <johnpol@2ka.mipt.ru> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'drivers/crypto/hifn_795x.c')
-rw-r--r--drivers/crypto/hifn_795x.c110
1 files changed, 108 insertions, 2 deletions
diff --git a/drivers/crypto/hifn_795x.c b/drivers/crypto/hifn_795x.c
index bf817d4ecae2..de594bc97742 100644
--- a/drivers/crypto/hifn_795x.c
+++ b/drivers/crypto/hifn_795x.c
@@ -19,6 +19,7 @@
19 19
20#include <linux/kernel.h> 20#include <linux/kernel.h>
21#include <linux/module.h> 21#include <linux/module.h>
22#include <linux/moduleparam.h>
22#include <linux/mod_devicetable.h> 23#include <linux/mod_devicetable.h>
23#include <linux/interrupt.h> 24#include <linux/interrupt.h>
24#include <linux/pci.h> 25#include <linux/pci.h>
@@ -47,6 +48,11 @@
47#define dprintk(f, a...) do {} while (0) 48#define dprintk(f, a...) do {} while (0)
48#endif 49#endif
49 50
51static char hifn_pll_ref[sizeof("extNNN")] = "ext";
52module_param_string(hifn_pll_ref, hifn_pll_ref, sizeof(hifn_pll_ref), 0444);
53MODULE_PARM_DESC(hifn_pll_ref,
54 "PLL reference clock (pci[freq] or ext[freq], default ext)");
55
50static atomic_t hifn_dev_number; 56static atomic_t hifn_dev_number;
51 57
52#define ACRYPTO_OP_DECRYPT 0 58#define ACRYPTO_OP_DECRYPT 0
@@ -286,7 +292,26 @@ static atomic_t hifn_dev_number;
286#define HIFN_DMACNFG_DMARESET 0x00000002 /* DMA Reset # */ 292#define HIFN_DMACNFG_DMARESET 0x00000002 /* DMA Reset # */
287#define HIFN_DMACNFG_MSTRESET 0x00000001 /* Master Reset # */ 293#define HIFN_DMACNFG_MSTRESET 0x00000001 /* Master Reset # */
288 294
289#define HIFN_PLL_7956 0x00001d18 /* 7956 PLL config value */ 295/* PLL configuration register */
296#define HIFN_PLL_REF_CLK_HBI 0x00000000 /* HBI reference clock */
297#define HIFN_PLL_REF_CLK_PLL 0x00000001 /* PLL reference clock */
298#define HIFN_PLL_BP 0x00000002 /* Reference clock bypass */
299#define HIFN_PLL_PK_CLK_HBI 0x00000000 /* PK engine HBI clock */
300#define HIFN_PLL_PK_CLK_PLL 0x00000008 /* PK engine PLL clock */
301#define HIFN_PLL_PE_CLK_HBI 0x00000000 /* PE engine HBI clock */
302#define HIFN_PLL_PE_CLK_PLL 0x00000010 /* PE engine PLL clock */
303#define HIFN_PLL_RESERVED_1 0x00000400 /* Reserved bit, must be 1 */
304#define HIFN_PLL_ND_SHIFT 11 /* Clock multiplier shift */
305#define HIFN_PLL_ND_MULT_2 0x00000000 /* PLL clock multiplier 2 */
306#define HIFN_PLL_ND_MULT_4 0x00000800 /* PLL clock multiplier 4 */
307#define HIFN_PLL_ND_MULT_6 0x00001000 /* PLL clock multiplier 6 */
308#define HIFN_PLL_ND_MULT_8 0x00001800 /* PLL clock multiplier 8 */
309#define HIFN_PLL_ND_MULT_10 0x00002000 /* PLL clock multiplier 10 */
310#define HIFN_PLL_ND_MULT_12 0x00002800 /* PLL clock multiplier 12 */
311#define HIFN_PLL_IS_1_8 0x00000000 /* charge pump (mult. 1-8) */
312#define HIFN_PLL_IS_9_12 0x00010000 /* charge pump (mult. 9-12) */
313
314#define HIFN_PLL_FCK_MAX 266 /* Maximum PLL frequency */
290 315
291/* Public key reset register (HIFN_1_PUB_RESET) */ 316/* Public key reset register (HIFN_1_PUB_RESET) */
292#define HIFN_PUBRST_RESET 0x00000001 /* reset public/rng unit */ 317#define HIFN_PUBRST_RESET 0x00000001 /* reset public/rng unit */
@@ -871,6 +896,64 @@ static void hifn_init_dma(struct hifn_device *dev)
871 dma->cmdk = dma->srck = dma->dstk = dma->resk = 0; 896 dma->cmdk = dma->srck = dma->dstk = dma->resk = 0;
872} 897}
873 898
899/*
900 * Initialize the PLL. We need to know the frequency of the reference clock
901 * to calculate the optimal multiplier. For PCI we assume 66MHz, since that
902 * allows us to operate without the risk of overclocking the chip. If it
903 * actually uses 33MHz, the chip will operate at half the speed, this can be
904 * overriden by specifying the frequency as module parameter (pci33).
905 *
906 * Unfortunately the PCI clock is not very suitable since the HIFN needs a
907 * stable clock and the PCI clock frequency may vary, so the default is the
908 * external clock. There is no way to find out its frequency, we default to
909 * 66MHz since according to Mike Ham of HiFn, almost every board in existence
910 * has an external crystal populated at 66MHz.
911 */
912static void hifn_init_pll(struct hifn_device *dev)
913{
914 unsigned int freq, m;
915 u32 pllcfg;
916
917 pllcfg = HIFN_1_PLL | HIFN_PLL_RESERVED_1;
918
919 if (strncmp(hifn_pll_ref, "ext", 3) == 0)
920 pllcfg |= HIFN_PLL_REF_CLK_PLL;
921 else
922 pllcfg |= HIFN_PLL_REF_CLK_HBI;
923
924 if (hifn_pll_ref[3] != '\0')
925 freq = simple_strtoul(hifn_pll_ref + 3, NULL, 10);
926 else {
927 freq = 66;
928 printk(KERN_INFO "hifn795x: assuming %uMHz clock speed, "
929 "override with hifn_pll_ref=%.3s<frequency>\n",
930 freq, hifn_pll_ref);
931 }
932
933 m = HIFN_PLL_FCK_MAX / freq;
934
935 pllcfg |= (m / 2 - 1) << HIFN_PLL_ND_SHIFT;
936 if (m <= 8)
937 pllcfg |= HIFN_PLL_IS_1_8;
938 else
939 pllcfg |= HIFN_PLL_IS_9_12;
940
941 /* Select clock source and enable clock bypass */
942 hifn_write_1(dev, HIFN_1_PLL, pllcfg |
943 HIFN_PLL_PK_CLK_HBI | HIFN_PLL_PE_CLK_HBI | HIFN_PLL_BP);
944
945 /* Let the chip lock to the input clock */
946 mdelay(10);
947
948 /* Disable clock bypass */
949 hifn_write_1(dev, HIFN_1_PLL, pllcfg |
950 HIFN_PLL_PK_CLK_HBI | HIFN_PLL_PE_CLK_HBI);
951
952 /* Switch the engines to the PLL */
953 hifn_write_1(dev, HIFN_1_PLL, pllcfg |
954 HIFN_PLL_PK_CLK_PLL | HIFN_PLL_PE_CLK_PLL);
955}
956
874static void hifn_init_registers(struct hifn_device *dev) 957static void hifn_init_registers(struct hifn_device *dev)
875{ 958{
876 u32 dptr = dev->desc_dma; 959 u32 dptr = dev->desc_dma;
@@ -938,7 +1021,7 @@ static void hifn_init_registers(struct hifn_device *dev)
938#else 1021#else
939 hifn_write_0(dev, HIFN_0_PUCNFG, 0x10342); 1022 hifn_write_0(dev, HIFN_0_PUCNFG, 0x10342);
940#endif 1023#endif
941 hifn_write_1(dev, HIFN_1_PLL, HIFN_PLL_7956); 1024 hifn_init_pll(dev);
942 1025
943 hifn_write_0(dev, HIFN_0_PUISR, HIFN_PUISR_DSTOVER); 1026 hifn_write_0(dev, HIFN_0_PUISR, HIFN_PUISR_DSTOVER);
944 hifn_write_1(dev, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET | 1027 hifn_write_1(dev, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET |
@@ -2621,8 +2704,31 @@ static struct pci_driver hifn_pci_driver = {
2621 2704
2622static int __devinit hifn_init(void) 2705static int __devinit hifn_init(void)
2623{ 2706{
2707 unsigned int freq;
2624 int err; 2708 int err;
2625 2709
2710 if (strncmp(hifn_pll_ref, "ext", 3) &&
2711 strncmp(hifn_pll_ref, "pci", 3)) {
2712 printk(KERN_ERR "hifn795x: invalid hifn_pll_ref clock, "
2713 "must be pci or ext");
2714 return -EINVAL;
2715 }
2716
2717 /*
2718 * For the 7955/7956 the reference clock frequency must be in the
2719 * range of 20MHz-100MHz. For the 7954 the upper bound is 66.67MHz,
2720 * but this chip is currently not supported.
2721 */
2722 if (hifn_pll_ref[3] != '\0') {
2723 freq = simple_strtoul(hifn_pll_ref + 3, NULL, 10);
2724 if (freq < 20 || freq > 100) {
2725 printk(KERN_ERR "hifn795x: invalid hifn_pll_ref "
2726 "frequency, must be in the range "
2727 "of 20-100");
2728 return -EINVAL;
2729 }
2730 }
2731
2626 err = pci_register_driver(&hifn_pci_driver); 2732 err = pci_register_driver(&hifn_pci_driver);
2627 if (err < 0) { 2733 if (err < 0) {
2628 dprintk("Failed to register PCI driver for %s device.\n", 2734 dprintk("Failed to register PCI driver for %s device.\n",