{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Read Zynq clock frequencies\n",
    "This example showing how to read the appropriate Zynq system registers to find the frequency of the ARM Cortex-A9 processor clock, and the four programmable logic clock frequencies.\n",
    "\n",
    "Other system registers can be read in a similar way. \n",
    "\n",
    "To find details on the Zynq system registers, see the Zynq TRM: http://www.xilinx.com/support/documentation/user_guides/ug585-Zynq-7000-TRM.pdf"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# Example PS Register Access Python\n",
    "# Calculating system clockrates from PS Register Values\n",
    "\n",
    "from pynq import MMIO as mmio\n",
    "\n",
    "# Zynq PS Constants\n",
    "SCLR_BASE             = 0xf8000000\n",
    "ZYNQ_NUM_FCLKS        = 4\n",
    "FCLK_CTRL_REG_OFFSETS = [0x170,0x180,0x190,0x1a0]\n",
    "\n",
    "\n",
    "def get_reg_value(addr):\n",
    "    '''Returns register value at address given.'''\n",
    "    return get_regfield_value(addr,0,0xffffffff)\n",
    "\n",
    "def get_regfield_value(addr,shift,mask):\n",
    "    '''Returns register field value at address.'''\n",
    "    currval = mmio(addr).read()\n",
    "    return (currval & (mask << shift)) >> shift\n",
    "\n",
    "def get_zynq_clockrates(src_clockrate=50):\n",
    "    '''Returns zynq system clockrates dictionary (in MHz).\n",
    "    \n",
    "    The returned dictionary has the following contents:\n",
    "    'cpu'  : Cortex-A9 freqency\n",
    "    'fclk0': PL fclk0 frequency\n",
    "    'fclk1': PL fclk1 frequency\n",
    "    'fclk2': PL fclk2 frequency\n",
    "    'fclk3': PL fclk3 frequency\n",
    "     \n",
    "    '''  \n",
    "    # Read Clock Registers from Zynq Memory Map\n",
    "    arm_pll_fdiv = get_regfield_value(SCLR_BASE+0x100,12,0x7f)\n",
    "    ddr_pll_fdiv = get_regfield_value(SCLR_BASE+0x104,12,0x7f)    \n",
    "    io_pll_fdiv = get_regfield_value(SCLR_BASE+0x108,12,0x7f)\n",
    "    \n",
    "    arm_clk_sel = get_regfield_value(SCLR_BASE+0x120,4,0x3)\n",
    "    arm_clk_div  = get_regfield_value(SCLR_BASE+0x120,8,0x3f)    \n",
    "    \n",
    "    fclk_config = list()\n",
    "    for ix,offset in enumerate(FCLK_CTRL_REG_OFFSETS): \n",
    "        fclk_config.append(dict())\n",
    "        fclk_config[ix][\"src\"] = get_regfield_value(\n",
    "                                    SCLR_BASE+offset,4,0x3)\n",
    "        fclk_config[ix][\"div0\"] = get_regfield_value(\n",
    "                                    SCLR_BASE+offset,8,0x3f)  \n",
    "        fclk_config[ix][\"div1\"] = get_regfield_value(\n",
    "                                    SCLR_BASE+offset,20,0x3f)\n",
    "        \n",
    "    # Calculate Clock rates based on register reads above\n",
    "    clock_values = list()\n",
    "    \n",
    "    # Arm clock\n",
    "    if arm_clk_sel == 0 or arm_clk_sel == 1 :\n",
    "        arm_clk_mult = arm_pll_fdiv\n",
    "    elif arm_clk_sel == 2:\n",
    "        arm_clk_mult = ddr_pll_fdiv\n",
    "    else:\n",
    "        arm_clk_mult = io_pll_fdiv\n",
    "        \n",
    "    armclk_value = src_clockrate*arm_clk_mult/arm_clk_div  \n",
    "    clock_values.append({\"cpu\" : armclk_value})\n",
    "    \n",
    "    # x4 fclks\n",
    "    for ix in range(4):\n",
    "        if fclk_config[ix][\"src\"] == 0 or \\\n",
    "                    fclk_config[ix][\"src\"] == 1:\n",
    "            fclk_mult = io_pll_fdiv            \n",
    "        elif fclk_config[ix][\"src\"] == 2:\n",
    "            fclk_mult = arm_pll_fdiv\n",
    "        else:\n",
    "            fclk_mult = ddr_pll_fdiv\n",
    "                \n",
    "        fclk_div0 = fclk_config[ix][\"div0\"]\n",
    "        fclk_div1 = fclk_config[ix][\"div1\"]\n",
    "    \n",
    "        fclk_value = src_clockrate*fclk_mult/ \\\n",
    "                            (fclk_div0*fclk_div1)\n",
    "        clock_values.append({\"fclk\" + str(ix) : \\\n",
    "                                     round(fclk_value,2)})\n",
    "        \n",
    "    return clock_values"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[{'cpu': 650.0},\n",
      " {'fclk0': 100.0},\n",
      " {'fclk1': 142.86},\n",
      " {'fclk2': 200.0},\n",
      " {'fclk3': 166.67}]\n"
     ]
    }
   ],
   "source": [
    "from pprint import pprint\n",
    "pprint(get_zynq_clockrates())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.4.3+"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
