Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 13 Jun 2012 20:52:58 +0000
From:      aleek@FreeBSD.org
To:        svn-soc-all@FreeBSD.org
Subject:   socsvn commit: r237628 - in soc2012/aleek/beaglexm-armv6/sys: arm/ti/am37x boot/fdt/dts
Message-ID:  <20120613205258.42647106564A@hub.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: aleek
Date: Wed Jun 13 20:52:57 2012
New Revision: 237628
URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=237628

Log:
  started to bringing up PRCM for omap3/am37x

Modified:
  soc2012/aleek/beaglexm-armv6/sys/arm/ti/am37x/am37x_prcm.c
  soc2012/aleek/beaglexm-armv6/sys/boot/fdt/dts/beagleboardxm.dts

Modified: soc2012/aleek/beaglexm-armv6/sys/arm/ti/am37x/am37x_prcm.c
==============================================================================
--- soc2012/aleek/beaglexm-armv6/sys/arm/ti/am37x/am37x_prcm.c	Wed Jun 13 19:53:29 2012	(r237627)
+++ soc2012/aleek/beaglexm-armv6/sys/arm/ti/am37x/am37x_prcm.c	Wed Jun 13 20:52:57 2012	(r237628)
@@ -1,5 +1,6 @@
 /*-
- * Copyright (c) 2012 Damjan Marion <dmarion@Freebsd.org>
+ * Copyright (c) 2011
+ *	Ben Gray <ben.r.gray@gmail.com>.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -11,10 +12,10 @@
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
@@ -29,130 +30,230 @@
 
 #include <sys/param.h>
 #include <sys/systm.h>
-#include <sys/bus.h>
 #include <sys/kernel.h>
 #include <sys/module.h>
-#include <sys/malloc.h>
+#include <sys/bus.h>
+#include <sys/resource.h>
 #include <sys/rman.h>
-#include <sys/timeet.h>
-#include <sys/timetc.h>
-#include <sys/watchdog.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+
 #include <machine/bus.h>
 #include <machine/cpu.h>
+#include <machine/cpufunc.h>
 #include <machine/frame.h>
+#include <machine/resource.h>
 #include <machine/intr.h>
 
 #include <arm/ti/tivar.h>
-#include <arm/ti/ti_scm.h>
 #include <arm/ti/ti_prcm.h>
+#include <arm/ti/am37x/am37x_reg.h>
 
-#include <dev/fdt/fdt_common.h>
-#include <dev/ofw/openfirm.h>
-#include <dev/ofw/ofw_bus.h>
-#include <dev/ofw/ofw_bus_subr.h>
 
-#include <machine/bus.h>
-#include <machine/fdt.h>
 
-#define CM_PER				0
-#define CM_PER_L4LS_CLKSTCTRL		(CM_PER + 0x000)
-#define CM_PER_L3S_CLKSTCTRL		(CM_PER + 0x004)
-#define CM_PER_L3_CLKSTCTRL		(CM_PER + 0x00C)
-#define CM_PER_CPGMAC0_CLKCTRL		(CM_PER + 0x014)
-#define CM_PER_USB0_CLKCTRL		(CM_PER + 0x01C)
-#define CM_PER_TPTC0_CLKCTRL		(CM_PER + 0x024)
-#define CM_PER_MMC0_CLKCTRL		(CM_PER + 0x03C)
-#define CM_PER_I2C2_CLKCTRL		(CM_PER + 0x044)
-#define CM_PER_I2C1_CLKCTRL		(CM_PER + 0x048)
-#define CM_PER_TIMER7_CLKCTRL		(CM_PER + 0x07C)
-#define CM_PER_TIMER2_CLKCTRL		(CM_PER + 0x080)
-#define CM_PER_TIMER3_CLKCTRL		(CM_PER + 0x084)
-#define CM_PER_TIMER4_CLKCTRL		(CM_PER + 0x088)
-#define CM_PER_GPIO1_CLKCTRL		(CM_PER + 0x0AC)
-#define CM_PER_GPIO2_CLKCTRL		(CM_PER + 0x0B0)
-#define CM_PER_GPIO3_CLKCTRL		(CM_PER + 0x0B4)
-#define CM_PER_TPCC_CLKCTRL		(CM_PER + 0x0BC)
-#define CM_PER_L3_INSTR_CLKCTRL		(CM_PER + 0x0DC)
-#define CM_PER_L3_CLKCTRL		(CM_PER + 0x0E0)
-#define CM_PER_TIMER5_CLKCTRL		(CM_PER + 0x0EC)
-#define CM_PER_TIMER6_CLKCTRL		(CM_PER + 0x0F0)
-#define CM_PER_MMC1_CLKCTRL		(CM_PER + 0x0F4)
-#define CM_PER_MMC2_CLKCTRL		(CM_PER + 0x0F8)
-#define CM_PER_TPTC1_CLKCTRL		(CM_PER + 0x0FC)
-#define CM_PER_TPTC2_CLKCTRL		(CM_PER + 0x100)
-#define CM_PER_OCPWP_L3_CLKSTCTRL	(CM_PER + 0x12C)
-#define CM_PER_OCPWP_CLKCTRL		(CM_PER + 0x130)
-#define CM_PER_CPSW_CLKSTCTRL		(CM_PER + 0x144)
-
-#define CM_WKUP				0x400
-#define CM_WKUP_CLKSTCTRL		(CM_WKUP + 0x000)
-#define CM_WKUP_CONTROL_CLKCTRL		(CM_WKUP + 0x004)
-#define CM_WKUP_GPIO0_CLKCTRL		(CM_WKUP + 0x008)
-#define CM_WKUP_CM_L3_AON_CLKSTCTRL	(CM_WKUP + 0x01C)
-#define CM_WKUP_CM_CLKSEL_DPLL_MPU	(CM_WKUP + 0x02C)
-#define CM_WKUP_CM_CLKDCOLDO_DPLL_PER	(CM_WKUP + 0x07C)
-#define CM_WKUP_I2C0_CLKCTRL		(CM_WKUP + 0x0B8)
-
-#define CM_DPLL				0x500
-#define CLKSEL_TIMER7_CLK		(CM_DPLL + 0x004)
-#define CLKSEL_TIMER2_CLK		(CM_DPLL + 0x008)
-#define CLKSEL_TIMER3_CLK		(CM_DPLL + 0x00C)
-#define CLKSEL_TIMER4_CLK		(CM_DPLL + 0x010)
-#define CLKSEL_TIMER5_CLK		(CM_DPLL + 0x018)
-#define CLKSEL_TIMER6_CLK		(CM_DPLL + 0x01C)
-
-#define PRM_DEVICE_OFFSET		0xF00
-#define PRM_RSTCTRL			(PRM_DEVICE_OFFSET + 0x00)
-
-struct am335x_prcm_softc {
-	struct resource *	res[2];
-	bus_space_tag_t		bst;
-	bus_space_handle_t	bsh;
-};
+/*
+ *	This file defines the clock configuration for the OMAP3xxx series of
+ *	devices.
+ *
+ *	How This is Suppose to Work
+ *	===========================
+ *	- There is a top level omap_prcm module that defines all OMAP SoC drivers
+ *	should use to enable/disable the system clocks regardless of the version
+ *	of OMAP device they are running on.  This top level PRCM module is just
+ *	a thin shim to chip specific functions that perform the donkey work of
+ *	configuring the clock - this file is the 'donkey' for OMAP35xx devices.
+ *
+ *	- The key bit in this file is the omap_clk_devmap array, it's
+ *	used by the omap_prcm driver to determine what clocks are valid and which
+ *	functions to call to manipulate them.
+ *
+ *	- In essence you just need to define some callbacks for each of the
+ *	clocks and then you're done.
+ *
+ *	- The other thing worth noting is that when the omap_prcm device
+ *	is registered you typically pass in some memory ranges which are the
+ *	SYS_MEMORY resources.  These resources are in turn allocated using 
+ *	bus_allocate_resources(...) and the resource handles are passed to all
+ *	individual clock callback handlers. 
+ *
+ *
+ *
+ *
+ */
 
-static struct resource_spec am335x_prcm_spec[] = {
-	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
-	{ -1, 0 }
-};
 
-static struct am335x_prcm_softc *am335x_prcm_sc = NULL;
+void
+omap3_clk_init(device_t dev, int prio);
 
-static int am335x_clk_generic_activate(struct ti_clock_dev *clkdev);
-static int am335x_clk_generic_deactivate(struct ti_clock_dev *clkdev);
-static int am335x_clk_generic_set_source(struct ti_clock_dev *clkdev, clk_src_t clksrc);
-static int am335x_clk_hsmmc_get_source_freq(struct ti_clock_dev *clkdev,  unsigned int *freq);
-static int am335x_clk_get_sysclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq);
-static int am335x_clk_get_arm_fclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq);
-static void am335x_prcm_reset(void);
-static int am335x_clk_cpsw_activate(struct ti_clock_dev *clkdev);
-static int am335x_clk_musb0_activate(struct ti_clock_dev *clkdev);
+static int
+omap3_clk_generic_activate(const struct ti_clock_dev *clkdev,
+                           struct resource* mem_res[]);
+
+static int
+omap3_clk_generic_deactivate(const struct ti_clock_dev *clkdev,
+                             struct resource* mem_res[]);
+
+static int
+omap3_clk_generic_accessible(const struct ti_clock_dev *clkdev,
+                             struct resource* mem_res[]);
+
+static int
+omap3_clk_generic_set_source(const struct ti_clock_dev *clkdev, clk_src_t clksrc,
+                             struct resource* mem_res[]);
+
+static int
+omap3_clk_generic_get_source_freq(const struct ti_clock_dev *clkdev,
+                                  unsigned int *freq,
+                                  struct resource* mem_res[]);
+
+
+static int
+omap3_clk_gptimer_get_source_freq(const struct ti_clock_dev *clkdev,
+                                  unsigned int *freq,
+                                  struct resource* mem_res[]);
+static int
+omap3_clk_gptimer_set_source(const struct ti_clock_dev *clkdev,
+                             clk_src_t clksrc, struct resource* mem_res[]);
+
+
+
+static int
+omap3_clk_alwayson_null_func(const struct ti_clock_dev *clkdev,
+                            struct resource* mem_res[]);
 
-#define AM335X_GENERIC_CLOCK_DEV(i) \
+
+
+static int
+omap3_clk_get_sysclk_freq(const struct ti_clock_dev *clkdev,
+                          unsigned int *freq, struct resource* mem_res[]);
+
+static int
+omap3_clk_get_arm_fclk_freq(const struct ti_clock_dev *clkdev,
+                            unsigned int *freq, struct resource* mem_res[]);
+
+
+
+static int
+omap3_clk_hsusbhost_activate(const struct ti_clock_dev *clkdev,
+                             struct resource* mem_res[]);
+
+static int
+omap3_clk_hsusbhost_deactivate(const struct ti_clock_dev *clkdev,
+                               struct resource* mem_res[]);
+
+
+
+
+#define FREQ_96MHZ    96000000
+#define FREQ_64MHZ    64000000
+#define FREQ_48MHZ    48000000
+#define FREQ_32KHZ    32000
+
+
+
+/**
+ *	Only one memory regions is needed for OMAP35xx clock control (unlike OMAP4)
+ *	
+ *	   CM Instance  -  0x4800 4000 : 0x4800 5500
+ *	   PRM Instance -  0x4830 6000 : 0x4830 8000
+ *
+ */
+#define CM_INSTANCE_MEM_REGION    0
+#define PRM_INSTANCE_MEM_REGION   1
+
+#define IVA2_CM_OFFSET            0x0000
+#define OCP_SYSTEM_CM_OFFSET      0x0800
+#define MPU_CM_OFFSET             0x0900
+#define CORE_CM_OFFSET            0x0A00
+#define SGX_CM_OFFSET             0x0B00
+#define WKUP_CM_OFFSET            0x0C00
+#define CLOCK_CTRL_CM_OFFSET      0x0D00
+#define DSS_CM_OFFSET             0x0E00
+#define CAM_CM_OFFSET             0x0F00
+#define PER_CM_OFFSET             0x1000
+#define EMU_CM_OFFSET             0x1100
+#define GLOBAL_CM_OFFSET          0x1200
+#define NEON_CM_OFFSET            0x1300
+#define USBHOST_CM_OFFSET         0x1400
+
+#define IVA2_PRM_OFFSET           0x0000
+#define OCP_SYSTEM_PRM_OFFSET     0x0800
+#define MPU_PRM_OFFSET            0x0900
+#define CORE_PRM_OFFSET           0x0A00
+#define SGX_PRM_OFFSET            0x0B00
+#define WKUP_PRM_OFFSET           0x0C00
+#define CLOCK_CTRL_PRM_OFFSET     0x0D00
+#define DSS_PRM_OFFSET            0x0E00
+#define CAM_PRM_OFFSET            0x0F00
+#define PER_PRM_OFFSET            0x1000
+#define EMU_PRM_OFFSET            0x1100
+#define GLOBAL_PRM_OFFSET         0x1200
+#define NEON_PRM_OFFSET           0x1300
+#define USBHOST_PRM_OFFSET        0x1400
+
+
+
+
+
+
+/**
+ *	omap_clk_devmap - Array of clock devices available on OMAP3xxx devices
+ *
+ *	This map only defines which clocks are valid and the callback functions
+ *	for clock activate, deactivate, etc.  It is used by the top level omap_prcm
+ *	driver.
+ *
+ *	The actual details of the clocks (config registers, bit fields, sources,
+ *	etc) are in the private g_omap3_clk_details array below.
+ *
+ */
+
+#define OMAP3_GENERIC_CLOCK_DEV(i) \
 	{	.id = (i), \
-		.clk_activate = am335x_clk_generic_activate, \
-		.clk_deactivate = am335x_clk_generic_deactivate, \
-		.clk_set_source = am335x_clk_generic_set_source, \
-		.clk_accessible = NULL, \
+		.clk_activate = omap3_clk_generic_activate, \
+		.clk_deactivate = omap3_clk_generic_deactivate, \
+		.clk_set_source = omap3_clk_generic_set_source, \
+		.clk_accessible = omap3_clk_generic_accessible, \
+		.clk_get_source_freq = omap3_clk_generic_get_source_freq \
+	}
+
+#define OMAP3_GPTIMER_CLOCK_DEV(i) \
+	{	.id = (i), \
+		.clk_activate = omap3_clk_generic_activate, \
+		.clk_deactivate = omap3_clk_generic_deactivate, \
+		.clk_set_source = omap3_clk_gptimer_set_source, \
+		.clk_accessible = omap3_clk_generic_accessible, \
+		.clk_get_source_freq = omap3_clk_gptimer_get_source_freq \
+	}
+
+#define OMAP3_ALWAYSON_CLOCK_DEV(i) \
+	{	.id = (i), \
+		.clk_activate = omap3_clk_alwayson_null_func, \
+		.clk_deactivate = omap3_clk_alwayson_null_func, \
+		.clk_set_source = NULL, \
+		.clk_accessible = omap3_clk_alwayson_null_func, \
 		.clk_get_source_freq = NULL \
 	}
 
-#define AM335X_MMCHS_CLOCK_DEV(i) \
+#define OMAP3_HSUSBHOST_CLOCK_DEV(i) \
 	{	.id = (i), \
-		.clk_activate = am335x_clk_generic_activate, \
-		.clk_deactivate = am335x_clk_generic_deactivate, \
-		.clk_set_source = am335x_clk_generic_set_source, \
-		.clk_accessible = NULL, \
-		.clk_get_source_freq = am335x_clk_hsmmc_get_source_freq \
+		.clk_activate = omap3_clk_hsusbhost_activate, \
+		.clk_deactivate = omap3_clk_hsusbhost_deactivate, \
+		.clk_set_source = NULL, \
+		.clk_accessible = omap3_clk_generic_accessible, \
+		.clk_get_source_freq = NULL \
 	}
 
-struct ti_clock_dev ti_clk_devmap[] = {
-	/* System clocks */
+
+const struct ti_clock_dev omap_clk_devmap[] = {
+
+	/* System clock */
 	{	.id                  = SYS_CLK,
 		.clk_activate        = NULL,
 		.clk_deactivate      = NULL,
 		.clk_set_source      = NULL,
 		.clk_accessible      = NULL,
-		.clk_get_source_freq = am335x_clk_get_sysclk_freq,
+		.clk_get_source_freq = omap3_clk_get_sysclk_freq,
 	},
 	/* MPU (ARM) core clocks */
 	{	.id                  = MPU_CLK,
@@ -160,375 +261,936 @@
 		.clk_deactivate      = NULL,
 		.clk_set_source      = NULL,
 		.clk_accessible      = NULL,
-		.clk_get_source_freq = am335x_clk_get_arm_fclk_freq,
-	},
-	/* CPSW Ethernet Switch core clocks */
-	{	.id                  = CPSW_CLK,
-		.clk_activate        = am335x_clk_cpsw_activate,
-		.clk_deactivate      = NULL,
-		.clk_set_source      = NULL,
-		.clk_accessible      = NULL,
-		.clk_get_source_freq = NULL,
+		.clk_get_source_freq = omap3_clk_get_arm_fclk_freq,
 	},
 
-	/* Mentor USB HS controller core clocks */
-	{	.id                  = MUSB0_CLK,
-		.clk_activate        = am335x_clk_musb0_activate,
-		.clk_deactivate      = NULL,
-		.clk_set_source      = NULL,
-		.clk_accessible      = NULL,
-		.clk_get_source_freq = NULL,
-	},
 
-	/* DMTimer */
-	AM335X_GENERIC_CLOCK_DEV(DMTIMER2_CLK),
-	AM335X_GENERIC_CLOCK_DEV(DMTIMER3_CLK),
-	AM335X_GENERIC_CLOCK_DEV(DMTIMER4_CLK),
-	AM335X_GENERIC_CLOCK_DEV(DMTIMER5_CLK),
-	AM335X_GENERIC_CLOCK_DEV(DMTIMER6_CLK),
-	AM335X_GENERIC_CLOCK_DEV(DMTIMER7_CLK),
+	/* UART device clocks */
+	OMAP3_GENERIC_CLOCK_DEV(UART1_CLK),
+	OMAP3_GENERIC_CLOCK_DEV(UART2_CLK),
+	OMAP3_GENERIC_CLOCK_DEV(UART3_CLK),
+	OMAP3_GENERIC_CLOCK_DEV(UART4_CLK),
+
+	/* Timer device source clocks */
+	OMAP3_GPTIMER_CLOCK_DEV(GPTIMER1_CLK),
+	OMAP3_GPTIMER_CLOCK_DEV(GPTIMER2_CLK),
+	OMAP3_GPTIMER_CLOCK_DEV(GPTIMER3_CLK),
+	OMAP3_GPTIMER_CLOCK_DEV(GPTIMER4_CLK),
+	OMAP3_GPTIMER_CLOCK_DEV(GPTIMER5_CLK),
+	OMAP3_GPTIMER_CLOCK_DEV(GPTIMER6_CLK),
+	OMAP3_GPTIMER_CLOCK_DEV(GPTIMER7_CLK),
+	OMAP3_GPTIMER_CLOCK_DEV(GPTIMER8_CLK),
+	OMAP3_GPTIMER_CLOCK_DEV(GPTIMER9_CLK),
+	OMAP3_GPTIMER_CLOCK_DEV(GPTIMER10_CLK),
+	OMAP3_GPTIMER_CLOCK_DEV(GPTIMER11_CLK),
+	
+	/* MMC device clocks (MMC1 and MMC2 can have different input clocks) */
+	OMAP3_GENERIC_CLOCK_DEV(MMC1_CLK),
+	OMAP3_GENERIC_CLOCK_DEV(MMC2_CLK),
+	OMAP3_GENERIC_CLOCK_DEV(MMC3_CLK),
+
+	/* USB HS (high speed TLL, EHCI and OHCI) */
+	OMAP3_GENERIC_CLOCK_DEV(USBTLL_CLK),
+	OMAP3_HSUSBHOST_CLOCK_DEV(USBHSHOST_CLK),
 
 	/* GPIO */
-	AM335X_GENERIC_CLOCK_DEV(GPIO0_CLK),
-	AM335X_GENERIC_CLOCK_DEV(GPIO1_CLK),
-	AM335X_GENERIC_CLOCK_DEV(GPIO2_CLK),
-	AM335X_GENERIC_CLOCK_DEV(GPIO3_CLK),
-
+	OMAP3_GENERIC_CLOCK_DEV(GPIO1_CLK),
+	OMAP3_GENERIC_CLOCK_DEV(GPIO2_CLK),
+	OMAP3_GENERIC_CLOCK_DEV(GPIO3_CLK),
+	OMAP3_GENERIC_CLOCK_DEV(GPIO4_CLK),
+	OMAP3_GENERIC_CLOCK_DEV(GPIO5_CLK),
+	OMAP3_GENERIC_CLOCK_DEV(GPIO6_CLK),
+	
 	/* I2C */
-	AM335X_GENERIC_CLOCK_DEV(I2C0_CLK),
-	AM335X_GENERIC_CLOCK_DEV(I2C1_CLK),
-	AM335X_GENERIC_CLOCK_DEV(I2C2_CLK),
-
-	/* EDMA */
-	AM335X_GENERIC_CLOCK_DEV(EDMA_TPCC_CLK),
-	AM335X_GENERIC_CLOCK_DEV(EDMA_TPTC0_CLK),
-	AM335X_GENERIC_CLOCK_DEV(EDMA_TPTC1_CLK),
-	AM335X_GENERIC_CLOCK_DEV(EDMA_TPTC2_CLK),
-
-	/* MMCHS */
-	AM335X_MMCHS_CLOCK_DEV(MMC0_CLK),
-	AM335X_MMCHS_CLOCK_DEV(MMC1_CLK),
-	AM335X_MMCHS_CLOCK_DEV(MMC2_CLK),
+	OMAP3_GENERIC_CLOCK_DEV(I2C1_CLK),
+	OMAP3_GENERIC_CLOCK_DEV(I2C2_CLK),
+	OMAP3_GENERIC_CLOCK_DEV(I2C3_CLK),
+
+	/* sDMA */
+	OMAP3_ALWAYSON_CLOCK_DEV(SDMA_CLK),	
 
 	{  INVALID_CLK_IDENT, NULL, NULL, NULL, NULL }
 };
 
-struct am335x_clk_details {
-	clk_ident_t	id;
-	uint32_t	clkctrl_reg;
-	uint32_t	clksel_reg;
+
+
+
+
+
+/**
+ *	g_omap3_clk_details - Stores details for all the different clocks supported
+ *
+ *	Whenever an operation on a clock is being performed (activated, deactivated,
+ *	etc) this array is looked up to find the correct register and bit(s) we
+ *	should be modifying.
+ *
+ */
+
+struct omap3_clk_details {
+	clk_ident_t id;
+	int32_t     src_freq;
+	
+	/* The register offset from the CM module register region of the registers*/
+	uint32_t    fclken_offset;
+	uint32_t    iclken_offset;
+	uint32_t    idlest_offset;
+	
+	/* The bit offset for the clock */
+	uint32_t    bit_offset;
 };
 
-#define _CLK_DETAIL(i, c, s) \
-	{	.id = (i), \
-		.clkctrl_reg = (c), \
-		.clksel_reg = (s), \
+#define OMAP3_GENERIC_CLOCK_DETAILS(d, freq, base, fclk, iclk, idlest, bit) \
+	{	.id = (d), \
+		.src_freq = (freq), \
+		.fclken_offset = ((base) + (fclk)), \
+		.iclken_offset = ((base) + (iclk)), \
+		.idlest_offset = ((base) + (idlest)), \
+		.bit_offset = (bit), \
 	}
 
-static struct am335x_clk_details g_am335x_clk_details[] = {
+static const struct omap3_clk_details g_omap3_clk_details[] = {
 
-	/* DMTimer modules */
-	_CLK_DETAIL(DMTIMER2_CLK, CM_PER_TIMER2_CLKCTRL, CLKSEL_TIMER2_CLK),
-	_CLK_DETAIL(DMTIMER3_CLK, CM_PER_TIMER3_CLKCTRL, CLKSEL_TIMER3_CLK),
-	_CLK_DETAIL(DMTIMER4_CLK, CM_PER_TIMER4_CLKCTRL, CLKSEL_TIMER4_CLK),
-	_CLK_DETAIL(DMTIMER5_CLK, CM_PER_TIMER5_CLKCTRL, CLKSEL_TIMER5_CLK),
-	_CLK_DETAIL(DMTIMER6_CLK, CM_PER_TIMER6_CLKCTRL, CLKSEL_TIMER6_CLK),
-	_CLK_DETAIL(DMTIMER7_CLK, CM_PER_TIMER7_CLKCTRL, CLKSEL_TIMER7_CLK),
+	/* UART */
+	OMAP3_GENERIC_CLOCK_DETAILS(UART1_CLK, FREQ_48MHZ, CORE_CM_OFFSET,
+		0x00, 0x10, 0x20, 13),
+	OMAP3_GENERIC_CLOCK_DETAILS(UART2_CLK, FREQ_48MHZ, CORE_CM_OFFSET,
+		0x00, 0x10, 0x20, 14),
+	OMAP3_GENERIC_CLOCK_DETAILS(UART3_CLK, FREQ_48MHZ, PER_CM_OFFSET,
+		0x00, 0x10, 0x20, 11),
+
+	/* General purpose timers */
+	OMAP3_GENERIC_CLOCK_DETAILS(GPTIMER1_CLK,  -1, WKUP_CM_OFFSET,
+		0x00, 0x10, 0x20, 3),
+	OMAP3_GENERIC_CLOCK_DETAILS(GPTIMER2_CLK,  -1, PER_CM_OFFSET,
+		0x00, 0x10, 0x20, 3),
+	OMAP3_GENERIC_CLOCK_DETAILS(GPTIMER3_CLK,  -1, PER_CM_OFFSET,
+		0x00, 0x10, 0x20, 4),
+	OMAP3_GENERIC_CLOCK_DETAILS(GPTIMER4_CLK,  -1, PER_CM_OFFSET,
+		0x00, 0x10, 0x20, 5),
+	OMAP3_GENERIC_CLOCK_DETAILS(GPTIMER5_CLK,  -1, PER_CM_OFFSET,
+		0x00, 0x10, 0x20, 6),
+	OMAP3_GENERIC_CLOCK_DETAILS(GPTIMER6_CLK,  -1, PER_CM_OFFSET,
+		0x00, 0x10, 0x20, 7),
+	OMAP3_GENERIC_CLOCK_DETAILS(GPTIMER7_CLK,  -1, PER_CM_OFFSET,
+		0x00, 0x10, 0x20, 8),
+	OMAP3_GENERIC_CLOCK_DETAILS(GPTIMER8_CLK,  -1, PER_CM_OFFSET,
+		0x00, 0x10, 0x20, 9),
+	OMAP3_GENERIC_CLOCK_DETAILS(GPTIMER9_CLK,  -1, PER_CM_OFFSET,
+		0x00, 0x10, 0x20, 10),
+	OMAP3_GENERIC_CLOCK_DETAILS(GPTIMER10_CLK, -1, CORE_CM_OFFSET,
+		0x00, 0x10, 0x20, 11),
+	OMAP3_GENERIC_CLOCK_DETAILS(GPTIMER11_CLK, -1, CORE_CM_OFFSET,
+		0x00, 0x10, 0x20, 12),
+
+	/* HSMMC (MMC1 and MMC2 can have different input clocks) */
+	OMAP3_GENERIC_CLOCK_DETAILS(MMC1_CLK, FREQ_96MHZ, CORE_CM_OFFSET,
+		0x00, 0x10, 0x20, 24),
+	OMAP3_GENERIC_CLOCK_DETAILS(MMC2_CLK, FREQ_96MHZ, CORE_CM_OFFSET,
+		0x00, 0x10, 0x20, 25),
+	OMAP3_GENERIC_CLOCK_DETAILS(MMC3_CLK, FREQ_96MHZ, CORE_CM_OFFSET,
+		0x00, 0x10, 0x20, 30),
+	
+	/* USB HS (high speed TLL, EHCI and OHCI) */
+	OMAP3_GENERIC_CLOCK_DETAILS(USBTLL_CLK, -1, CORE_CM_OFFSET,
+		0x08, 0x18, 0x28, 2),
+	OMAP3_GENERIC_CLOCK_DETAILS(USBHSHOST_CLK, -1, USBHOST_CM_OFFSET,
+		0x00, 0x10, 0x20, 1),
 
 	/* GPIO modules */
-	_CLK_DETAIL(GPIO0_CLK, CM_WKUP_GPIO0_CLKCTRL, 0),
-	_CLK_DETAIL(GPIO1_CLK, CM_PER_GPIO1_CLKCTRL, 0),
-	_CLK_DETAIL(GPIO2_CLK, CM_PER_GPIO2_CLKCTRL, 0),
-	_CLK_DETAIL(GPIO3_CLK, CM_PER_GPIO3_CLKCTRL, 0),
-
+	OMAP3_GENERIC_CLOCK_DETAILS(GPIO1_CLK, -1, WKUP_CM_OFFSET,
+		0x00, 0x10, 0x20, 3),
+	OMAP3_GENERIC_CLOCK_DETAILS(GPIO2_CLK, -1, PER_CM_OFFSET,
+		0x00, 0x10, 0x20, 13),
+	OMAP3_GENERIC_CLOCK_DETAILS(GPIO3_CLK, -1, PER_CM_OFFSET,
+		0x00, 0x10, 0x20, 14),
+	OMAP3_GENERIC_CLOCK_DETAILS(GPIO4_CLK, -1, PER_CM_OFFSET,
+		0x00, 0x10, 0x20, 15),
+	OMAP3_GENERIC_CLOCK_DETAILS(GPIO5_CLK, -1, PER_CM_OFFSET,
+		0x00, 0x10, 0x20, 16),
+	OMAP3_GENERIC_CLOCK_DETAILS(GPIO6_CLK, -1, PER_CM_OFFSET,
+		0x00, 0x10, 0x20, 17),
+		
 	/* I2C modules */
-	_CLK_DETAIL(I2C0_CLK, CM_WKUP_I2C0_CLKCTRL, 0),
-	_CLK_DETAIL(I2C1_CLK, CM_PER_I2C1_CLKCTRL, 0),
-	_CLK_DETAIL(I2C2_CLK, CM_PER_I2C2_CLKCTRL, 0),
-
-	/* EDMA modules */
-	_CLK_DETAIL(EDMA_TPCC_CLK, CM_PER_TPCC_CLKCTRL, 0),
-	_CLK_DETAIL(EDMA_TPTC0_CLK, CM_PER_TPTC0_CLKCTRL, 0),
-	_CLK_DETAIL(EDMA_TPTC1_CLK, CM_PER_TPTC1_CLKCTRL, 0),
-	_CLK_DETAIL(EDMA_TPTC2_CLK, CM_PER_TPTC2_CLKCTRL, 0),
-
-	/* MMCHS modules*/
-	_CLK_DETAIL(MMC0_CLK, CM_PER_MMC0_CLKCTRL, 0),
-	_CLK_DETAIL(MMC1_CLK, CM_PER_MMC1_CLKCTRL, 0),
-	_CLK_DETAIL(MMC2_CLK, CM_PER_MMC1_CLKCTRL, 0),
+	OMAP3_GENERIC_CLOCK_DETAILS(I2C1_CLK, -1, CORE_CM_OFFSET,
+		0x00, 0x10, 0x20, 15),
+	OMAP3_GENERIC_CLOCK_DETAILS(I2C2_CLK, -1, CORE_CM_OFFSET,
+		0x00, 0x10, 0x20, 16),
+	OMAP3_GENERIC_CLOCK_DETAILS(I2C3_CLK, -1, CORE_CM_OFFSET,
+		0x00, 0x10, 0x20, 17),
 
-	{ INVALID_CLK_IDENT, 0},
+
+	{ INVALID_CLK_IDENT, 0, 0, 0, 0 },
 };
 
-/* Read/Write macros */
-#define prcm_read_4(reg)		\
-	bus_space_read_4(am335x_prcm_sc->bst, am335x_prcm_sc->bsh, reg)
-#define prcm_write_4(reg, val)		\
-	bus_space_write_4(am335x_prcm_sc->bst, am335x_prcm_sc->bsh, reg, val)
 
-void am335x_prcm_setup_dmtimer(int);
 
+
+
+
+/**
+ *	MAX_MODULE_ENABLE_WAIT - the number of loops to wait for the module to come
+ *	alive.
+ *
+ */
+#define MAX_MODULE_ENABLE_WAIT    1000
+
+	
+/**
+ *	ARRAY_SIZE - Macro to return the number of elements in a static const array.
+ *
+ */
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+
+
+
+
+/**
+ *	omap3_clk_wait_on_reg - loops for MAX_MODULE_ENABLE_WAIT times or until
+ *	                        register bit(s) change.
+ *	@mem_res: memory resource of the register to read
+ *	@off: offset of the register within mem_res
+ *	@mask: the mask to bitwise AND with the register
+ *	@cmp: if this value matches the register value after the mask is applied
+ *	      the function returns with 0.
+ *
+ *
+ *	RETURNS:
+ *	Returns 0 on success or ETIMEDOUT on failure.
+ */
 static int
-am335x_prcm_probe(device_t dev)
+omap3_clk_wait_on_reg(struct resource* mem_res, bus_size_t off, uint32_t mask,
+                      uint32_t cmp)
 {
-	if (ofw_bus_is_compatible(dev, "am335x,prcm")) {
-		device_set_desc(dev, "AM335x Power and Clock Management");
-		return(BUS_PROBE_DEFAULT);
+	unsigned int i;
+	for (i = 0; i < MAX_MODULE_ENABLE_WAIT; i++) {
+		if ((bus_read_4(mem_res, off) & mask) == cmp)
+			return (0);
 	}
 
-	return (ENXIO);
+	return (ETIMEDOUT);
 }
 
-static int
-am335x_prcm_attach(device_t dev)
-{
-	struct am335x_prcm_softc *sc = device_get_softc(dev);
-	unsigned int sysclk, fclk;
 
-	if (am335x_prcm_sc)
-		return (ENXIO);
 
-	if (bus_alloc_resources(dev, am335x_prcm_spec, sc->res)) {
-		device_printf(dev, "could not allocate resources\n");
-		return (ENXIO);
+
+
+/**
+ *	omap3_clk_details - returns a pointer to the generic clock details
+ *	@id: The ID of the clock to get the details for
+ *
+ *	This function iterates over the g_omap3_clk_details array and returns a
+ *	pointer to the entry that matches the supplied ID, or NULL if no entry
+ *	is found.
+ *
+ *	RETURNS:
+ *	Pointer to clock details or NULL on failure
+ */
+static const struct omap3_clk_details*
+omap3_clk_details(clk_ident_t id)
+{
+	const struct omap3_clk_details *walker;
+
+	for (walker = g_omap3_clk_details; walker->id != INVALID_CLK_IDENT; walker++) {
+		if (id == walker->id)
+			return (walker);
 	}
 
-	sc->bst = rman_get_bustag(sc->res[0]);
-	sc->bsh = rman_get_bushandle(sc->res[0]);
+	return NULL;
+}
 
-	am335x_prcm_sc = sc;
-	ti_cpu_reset = am335x_prcm_reset;
 
-	am335x_clk_get_sysclk_freq(NULL, &sysclk);
-	am335x_clk_get_arm_fclk_freq(NULL, &fclk);
-	device_printf(dev, "Clocks: System %u.%01u MHz, CPU %u MHz\n",
-		sysclk/1000000, (sysclk % 1000000)/100000, fclk/1000000);
 
+
+/**
+ *	omap3_clk_alwayson_null_func - dummy function for always on clocks
+ *	@clkdev: pointer to the clock device structure (ignored)
+ *	@mem_res: array of memory resources mapped when PRCM driver attached (ignored)
+ *	
+ *	
+ *
+ *	LOCKING:
+ *	Inherits the locks from the omap_prcm driver, no internal locking.
+ *
+ *	RETURNS:
+ *	Returns 0 on success or a positive error code on failure.
+ */
+static int
+omap3_clk_alwayson_null_func(const struct ti_clock_dev *clkdev,
+                             struct resource* mem_res[])
+{
 	return (0);
 }
 
-static device_method_t am335x_prcm_methods[] = {
-	DEVMETHOD(device_probe,		am335x_prcm_probe),
-	DEVMETHOD(device_attach,	am335x_prcm_attach),
-	{ 0, 0 }
-};
 
-static driver_t am335x_prcm_driver = {
-	"am335x_prcm",
-	am335x_prcm_methods,
-	sizeof(struct am335x_prcm_softc),
-};
 
-static devclass_t am335x_prcm_devclass;
 
-DRIVER_MODULE(am335x_prcm, simplebus, am335x_prcm_driver,
-	am335x_prcm_devclass, 0, 0);
-MODULE_DEPEND(am335x_prcm, ti_scm, 1, 1, 1);
 
-static struct am335x_clk_details*
-am335x_clk_details(clk_ident_t id)
+/**
+ *	omap3_clk_get_sysclk_freq - gets the sysclk frequency
+ *	@sc: pointer to the clk module/device context
+ *
+ *	Read the clocking information from the power-control/boot-strap registers,
+ *  and stored in two global variables.
+ *
+ *	RETURNS:
+ *	nothing, values are saved in global variables
+ */
+static int
+omap3_clk_get_sysclk_freq(const struct ti_clock_dev *clkdev,
+                          unsigned int *freq, struct resource* mem_res[])
 {
-	struct am335x_clk_details *walker;
+	uint32_t clksel;
+	uint32_t clknsel;
+	unsigned int oscclk;
+	unsigned int sysclk;
+	
+	/* Read the input clock freq from the configuration register */
+	clknsel = bus_read_4(mem_res[PRM_INSTANCE_MEM_REGION], CLOCK_CTRL_PRM_OFFSET + 0x40);
+	switch (clknsel & 0x7) {
+		case 0x0:
+			/* 12Mhz */
+			oscclk = 12000000;
+			break;
+		case 0x1:
+			/* 13Mhz */
+			oscclk = 13000000;
+			break;
+		case 0x2:
+			/* 19.2Mhz */
+			oscclk = 19200000;
+			break;
+		case 0x3:
+			/* 26Mhz */
+			oscclk = 26000000;
+			break;
+		case 0x4:
+			/* 38.4Mhz */
+			oscclk = 38400000;
+			break;
+		case 0x5:
+			/* 16.8Mhz */
+			oscclk = 16800000;
+			break;
+		default:
+			panic("%s: Invalid clock freq", __func__);
+	}
 
-	for (walker = g_am335x_clk_details; walker->id != INVALID_CLK_IDENT; walker++) {
-		if (id == walker->id)
-			return (walker);
+	/* Read the value of the clock divider used for the system clock */
+	clksel = bus_read_4(mem_res[PRM_INSTANCE_MEM_REGION], GLOBAL_PRM_OFFSET + 0x70);
+	switch (clksel & 0xC0) {
+		case 0x40:
+			sysclk = oscclk;
+			break;
+		case 0x80:
+			sysclk = oscclk / 2;
+			break;
+		default:
+			panic("%s: Invalid system clock divider", __func__);
 	}
 
-	return NULL;
+	/* Return the value */
+	if (freq)
+		*freq = sysclk;
+
+	return (0);
 }
 
+
+
+/**
+ *	omap3_clk_get_arm_fclk_freq - gets the MPU clock frequency
+ *	@clkdev: ignored
+ *	@freq: pointer which upon return will contain the freq in hz
+ *	@mem_res: array of allocated memory resources
+ *
+ *	Reads the frequency setting information registers and returns the value
+ *	in the freq variable.
+ *
+ *	RETURNS:
+ *	returns 0 on success, a positive error code on failure.
+ */
 static int
-am335x_clk_generic_activate(struct ti_clock_dev *clkdev)
+omap3_clk_get_arm_fclk_freq(const struct ti_clock_dev *clkdev,
+                            unsigned int *freq, struct resource* mem_res[])
 {
-	struct am335x_prcm_softc *sc = am335x_prcm_sc;
-	struct am335x_clk_details* clk_details;
+	unsigned int sysclk;
+	unsigned int coreclk;
+	unsigned int mpuclk;
+	uint32_t clksel;
+	uint32_t clkout;
+
+
+	/* Get the SYSCLK freq */
+	omap3_clk_get_sysclk_freq(clkdev, &sysclk, mem_res);
+	
+	
+	/* First get the freq of the CORE_CLK (feed from DPLL3) */
+	clksel = bus_read_4(mem_res[CM_INSTANCE_MEM_REGION], CLOCK_CTRL_CM_OFFSET + 0x40);
+	clkout = (sysclk * ((clksel >> 16) & 0x7FF)) / (((clksel >> 8) & 0x7F) + 1);
+	coreclk = clkout / (clksel >> 27);
+
+
+	/* Next get the freq for the MPU_CLK */
+	clksel = bus_read_4(mem_res[CM_INSTANCE_MEM_REGION], MPU_CM_OFFSET + 0x40);
+	mpuclk = (coreclk * ((clksel >> 8) & 0x7FF)) / ((clksel & 0x7F) + 1);
+
+
+	/* Return the value */
+	if (freq)
+		*freq = mpuclk;
+
+	return (0);
+}
+
+
+
+
 
-	if (sc == NULL)
-		return ENXIO;
 
-	clk_details = am335x_clk_details(clkdev->id);
+
+	
+/**
+ *	omap3_clk_generic_activate - activates a modules iinterface and func clock
+ *	@clkdev: pointer to the clock device structure.
+ *	@mem_res: array of memory resources mapped when PRCM driver attached
+ *	
+ *	
+ *
+ *	LOCKING:
+ *	Inherits the locks from the omap_prcm driver, no internal locking.
+ *
+ *	RETURNS:
+ *	Returns 0 on success or a positive error code on failure.
+ */
+static int
+omap3_clk_generic_activate(const struct ti_clock_dev *clkdev,
+                           struct resource* mem_res[])
+{
+	const struct omap3_clk_details* clk_details = omap3_clk_details(clkdev->id);
+	struct resource* clk_mem_res = mem_res[CM_INSTANCE_MEM_REGION];
+	uint32_t fclken, iclken;
 
 	if (clk_details == NULL)
 		return (ENXIO);
+	if (clk_mem_res == NULL)
+		return (ENOMEM);
+	
+	
+	/* All the 'generic' clocks have a FCLKEN, ICLKEN and IDLEST register which
+	 * is for the functional, interface and clock status regsters respectively.
+	 */
+	 
+	/* Enable the interface clock */
+	iclken = bus_read_4(clk_mem_res, clk_details->iclken_offset);
+	iclken |= (1UL << clk_details->bit_offset);
+	bus_write_4(clk_mem_res, clk_details->iclken_offset, iclken);
+	
+	/* Read back the value to ensure the write has taken place ... needed ? */
+	iclken = bus_read_4(clk_mem_res, clk_details->iclken_offset);
+
+
+	/* Enable the functional clock */
+	fclken = bus_read_4(clk_mem_res, clk_details->fclken_offset);
+	fclken |= (1UL << clk_details->bit_offset);
+	bus_write_4(clk_mem_res, clk_details->fclken_offset, fclken);
+
+	/* Read back the value to ensure the write has taken place ... needed ? */
+	fclken = bus_read_4(clk_mem_res, clk_details->fclken_offset);
+
+
+	/* Now poll on the IDLEST register to tell us if the module has come up.
+	 * TODO: We need to take into account the parent clocks.
+	 */
+	
+	/* Try MAX_MODULE_ENABLE_WAIT number of times to check if enabled */
+	if (omap3_clk_wait_on_reg(clk_mem_res, clk_details->idlest_offset,
+	                          (1UL << clk_details->bit_offset), 0) != 0) {
+		printf("Error: failed to enable module with clock %d\n", clkdev->id);
+		return (ETIMEDOUT);
+	}
+	
+	return (0);
+}
 
-	/* set *_CLKCTRL register MODULEMODE[1:0] to enable(2) */
-	prcm_write_4(clk_details->clkctrl_reg, 2);
-	while ((prcm_read_4(clk_details->clkctrl_reg) & 0x3) != 2)
-		DELAY(10);
 
+
+/**
+ *	omap3_clk_generic_deactivate - deactivates a modules clock
+ *	@clkdev: pointer to the clock device structure.
+ *	@mem_res: array of memory resources mapped when PRCM driver attached
+ *	
+ *	
+ *
+ *	LOCKING:
+ *	Inherits the locks from the omap_prcm driver, no internal locking.
+ *
+ *	RETURNS:
+ *	Returns 0 on success or a positive error code on failure.
+ */
+static int
+omap3_clk_generic_deactivate(const struct ti_clock_dev *clkdev,
+                             struct resource* mem_res[])
+{
+	const struct omap3_clk_details* clk_details = omap3_clk_details(clkdev->id);
+	struct resource* clk_mem_res = mem_res[CM_INSTANCE_MEM_REGION];
+	uint32_t fclken, iclken;
+
+	if (clk_details == NULL)
+		return (ENXIO);
+	if (clk_mem_res == NULL)
+		return (ENOMEM);
+	
+	
+	/* All the 'generic' clocks have a FCLKEN, ICLKEN and IDLEST register which
+	 * is for the functional, interface and clock status regsters respectively.
+	 */
+	 
+	/* Disable the interface clock */
+	iclken = bus_read_4(clk_mem_res, clk_details->iclken_offset);
+	iclken &= ~(1UL << clk_details->bit_offset);
+	bus_write_4(clk_mem_res, clk_details->iclken_offset, iclken);
+
+	/* Disable the functional clock */
+	fclken = bus_read_4(clk_mem_res, clk_details->fclken_offset);
+	fclken &= ~(1UL << clk_details->bit_offset);
+	bus_write_4(clk_mem_res, clk_details->fclken_offset, fclken);
+
+	
 	return (0);
 }
 
+
+/**
+ *	omap3_clk_generic_set_source - checks if a module is accessible
+ *	@clkdev: pointer to the clock device structure.
+ *	
+ *	
+ *
+ *	LOCKING:
+ *	Inherits the locks from the omap_prcm driver, no internal locking.
+ *

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20120613205258.42647106564A>