Logo Search packages:      
Sourcecode: linux-fsl-imx51 version File versions  Download package

static int scc_init ( void   )  [static]

Initialize the driver at boot time or module load time.

Register with the kernel as the interrupt handler for the SCC interrupt line(s).

Map the SCC's register space into the driver's memory space.

Query the SCC for its configuration and status. Save the configuration in scc_configuration and save the status in scc_availability. Called by the kernel.

Do any locking/wait queue initialization which may be necessary.

The availability fuse may be checked, depending on platform.

The error could be only that the SCM interrupt was not set up. This interrupt is always masked, so that is not an issue. The SMN's interrupt may be shared on that line, it may be separate, or it may not be wired. Do what is necessary to check its status. Although the driver is coded for possibility of not having SMN interrupt, the fact that there is one means it should be available and used.

Definition at line 501 of file scc2_driver.c.

References FALSE, os_lock_alloc_init(), os_printk, scc_config_t::partition_count, scc_config_t::partition_size_bytes, scc_availability, scc_base, SCC_CALLBACK_SIZE, scc_callbacks, scc_callbacks_lock, scc_cleanup(), scc_crypto_lock, scc_grab_config_values(), scc_init_ccitt_crc(), SCC_READ_REGISTER, SCC_STATUS_CHECKING, SCC_STATUS_FAILED, SCC_STATUS_INITIAL, SCC_STATUS_OK, SCC_STATUS_UNIMPLEMENTED, SCC_WRITE_REGISTER, SCM_ERR_STATUS_REG, SCM_INT_CTL_REG, scm_irq_set, setup_interrupt_handling(), SMN_COMMAND_CLEAR_INTERRUPT, SMN_COMMAND_ENABLE_INTERRUPT, SMN_COMMAND_REG, and smn_irq_set.

{
      uint32_t smn_status;
      int i;
      int return_value = -EIO;      /* assume error */

      if (scc_availability == SCC_STATUS_INITIAL) {

            /* Set this until we get an initial reading */
            scc_availability = SCC_STATUS_CHECKING;

            /* Initialize the constant for the CRC function */
            scc_init_ccitt_crc();

            /* initialize the callback table */
            for (i = 0; i < SCC_CALLBACK_SIZE; i++) {
                  scc_callbacks[i] = 0;
            }

#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18))
            mxc_clks_enable(SCC_CLK);
#else
            scc_clk = clk_get(NULL, "scc_clk");
            if (scc_clk != ERR_PTR(ENOENT)) {
                  clk_enable(scc_clk);
            }
#endif

            /* Set up the hardware access locks */
            scc_callbacks_lock = os_lock_alloc_init();
            scc_crypto_lock = os_lock_alloc_init();
            if (scc_callbacks_lock == NULL || scc_crypto_lock == NULL) {
                  os_printk(KERN_ERR
                          "SCC2: Failed to allocate context locks.  Exiting.\n");
                  goto out;
            }

            /* See whether there is an SCC available */
            if (0 && !SCC_ENABLED()) {
                  os_printk(KERN_ERR
                          "SCC2: Fuse for SCC is set to disabled.  Exiting.\n");
                  goto out;
            }
            /* Map the SCC (SCM and SMN) memory on the internal bus into
               kernel address space */
            scc_base = (void *)IO_ADDRESS(SCC_BASE);
            if (scc_base == NULL) {
                  os_printk(KERN_ERR
                          "SCC2: Register mapping failed.  Exiting.\n");
                  goto out;
            }

            /* If that worked, we can try to use the SCC */
            /* Get SCM into 'clean' condition w/interrupts cleared &
               disabled */
            SCC_WRITE_REGISTER(SCM_INT_CTL_REG, 0);

            /* Clear error status register */
            (void)SCC_READ_REGISTER(SCM_ERR_STATUS_REG);

            /*
             * There is an SCC.  Determine its current state.  Side effect
             * is to populate scc_config and scc_availability
             */
            smn_status = scc_grab_config_values();

            /* Try to set up interrupt handler(s) */
            if (scc_availability != SCC_STATUS_OK) {
                  goto out;
            }

            if (cpu_is_mx51_rev(CHIP_REV_2_0) < 0)
                  scm_ram_phys_base += 0x8000;

            scm_ram_base = (void *)ioremap_nocache(scm_ram_phys_base,
                                           scc_configuration.
                                           partition_count *
                                           scc_configuration.
                                           partition_size_bytes);
            if (scm_ram_base == NULL) {
                  os_printk(KERN_ERR
                          "SCC2: RAM failed to remap: %p for %d bytes\n",
                          (void *)scm_ram_phys_base,
                          scc_configuration.partition_count *
                          scc_configuration.partition_size_bytes);
                  goto out;
            }
            pr_debug("SCC2: RAM at Physical %p / Virtual %p\n",
                   (void *)scm_ram_phys_base, scm_ram_base);

            pr_debug("Secure Partition Table: Found %i partitions\n",
                   scc_configuration.partition_count);

            if (setup_interrupt_handling() != 0) {
                  unsigned err_cond;
          /**
            * The error could be only that the SCM interrupt was
            * not set up.  This interrupt is always masked, so
            * that is not an issue.
            * The SMN's interrupt may be shared on that line, it
            * may be separate, or it may not be wired.  Do what
            * is necessary to check its status.
            * Although the driver is coded for possibility of not
            * having SMN interrupt, the fact that there is one
            * means it should be available and used.
            */
#ifdef USE_SMN_INTERRUPT
                  err_cond = !smn_irq_set;      /* Separate. Check SMN binding */
#elif !defined(NO_SMN_INTERRUPT)
                  err_cond = !scm_irq_set;      /* Shared. Check SCM binding */
#else
                  err_cond = FALSE; /*  SMN not wired at all.  Ignore. */
#endif
                  if (err_cond) {
                        /* setup was not able to set up SMN interrupt */
                        scc_availability = SCC_STATUS_UNIMPLEMENTED;
                        goto out;
                  }
            }

            /* interrupt handling returned non-zero */
            /* Get SMN into 'clean' condition w/interrupts cleared &
               enabled */
            SCC_WRITE_REGISTER(SMN_COMMAND_REG,
                           SMN_COMMAND_CLEAR_INTERRUPT
                           | SMN_COMMAND_ENABLE_INTERRUPT);

            out:
            /*
             * If status is SCC_STATUS_UNIMPLEMENTED or is still
             * SCC_STATUS_CHECKING, could be leaving here with the driver partially
             * initialized.  In either case, cleanup (which will mark the SCC as
             * UNIMPLEMENTED).
             */
            if (scc_availability == SCC_STATUS_CHECKING ||
                scc_availability == SCC_STATUS_UNIMPLEMENTED) {
                  scc_cleanup();
            } else {
                  return_value = 0; /* All is well */
            }
      }
      /* ! STATUS_INITIAL */
      os_printk(KERN_ALERT "SCC2: Driver Status is %s\n",
              (scc_availability == SCC_STATUS_INITIAL) ? "INITIAL" :
              (scc_availability == SCC_STATUS_CHECKING) ? "CHECKING" :
              (scc_availability ==
               SCC_STATUS_UNIMPLEMENTED) ? "UNIMPLEMENTED"
              : (scc_availability ==
                 SCC_STATUS_OK) ? "OK" : (scc_availability ==
                                    SCC_STATUS_FAILED) ? "FAILED" :
              "UNKNOWN");

#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
                  mxc_clks_disable(SCC_CLK);
#else
                  if (scc_clk != ERR_PTR(ENOENT))
                        clk_disable(scc_clk);
#endif

      return return_value;
}                       /* scc_init */


Generated by  Doxygen 1.6.0   Back to index